# Open WebUI SQLite Model List

Open WebUI stores model IDs in **TWO separate locations** inside its SQLite database. Both must be in sync for new models to appear in the UI.

## Location 1: `config` table (OpenAI Provider Model List)

```
/app/backend/data/webui.db
  → table: config
    → column: data (JSON blob)
      → key: openai.api_configs.0.model_ids (array of strings)
```

Controls which model IDs the OpenAI backend (llama-swap) advertises. Usually auto-populated.

### Diagnostic
```bash
docker exec open-webui python3 -c "
import sqlite3, json
conn = sqlite3.connect('/app/backend/data/webui.db')
row = conn.execute('SELECT id, data FROM config LIMIT 1').fetchone()
config = json.loads(row[1])
for m in config['openai']['api_configs']['0']['model_ids']:
    print(f'  {m}')
conn.close()
"
```

## Location 2: `model` table (Per-User Model Registry)

**Primary location** that determines which models appear in the UI dropdown. A model listed in `config` but missing from `model` will not be selectable.

### Schema
```
table: model
columns: id, user_id, base_model_id, name, meta, params, created_at, updated_at, is_active
```
- `id` = `model-<base-model-id>` (prefixed with `model-`)
- `user_id` = admin user UUID (from `user` table)
- `base_model_id` = model ID as known by llama-swap (must match exactly)
- `meta` = `'{}'`, `params` = `'{}'`
- `is_active` = `1`

### Diagnostic
```bash
docker exec open-webui python3 -c "
import sqlite3
conn = sqlite3.connect('/app/backend/data/webui.db')
for r in conn.execute('SELECT id, base_model_id, name, is_active FROM model ORDER BY id'):
    print(f'  {r[0]:40s} active={r[1]}')
conn.close()
"
```

### Add a New Model
```python
import sqlite3, time
conn = sqlite3.connect('/app/backend/data/webui.db')
user_id = conn.execute("SELECT id FROM user WHERE role = 'admin' LIMIT 1").fetchone()[0]
now = int(time.time())

model_id = '<model-id>'  # as known by llama-swap
existing = conn.execute("SELECT id FROM model WHERE base_model_id = ?", (model_id,)).fetchone()
if not existing:
    conn.execute(
        "INSERT INTO model (id, user_id, base_model_id, name, meta, params, created_at, updated_at, is_active) "
        "VALUES (?, ?, ?, ?, '{}', '{}', ?, ?, 1)",
        (f'model-{model_id}', user_id, model_id, model_id, now, now)
    )
    print(f'Added: {model_id}')
conn.commit()
conn.close()
```

### Bulk Sync (Match llama-swap Fleet Exactly)
```python
import sqlite3, json, time, urllib.request

resp = urllib.request.urlopen('http://127.0.0.1:9292/v1/models', timeout=5)
swaps_models = [m['id'] for m in json.loads(resp.read())['data']]

conn = sqlite3.connect('/app/backend/data/webui.db')
user_id = conn.execute("SELECT id FROM user WHERE role = 'admin' LIMIT 1").fetchone()[0]
now = int(time.time())

for mid in swaps_models:
    if not conn.execute("SELECT id FROM model WHERE base_model_id = ?", (mid,)).fetchone():
        conn.execute("INSERT INTO model (id, user_id, base_model_id, name, meta, params, created_at, updated_at, is_active) VALUES (?, ?, ?, ?, '{}', '{}', ?, ?, 1)", (f'model-{mid}', user_id, mid, mid, now, now))
        print(f'Added: {mid}')

current = set(swaps_models)
for row in conn.execute("SELECT id, base_model_id FROM model"):
    if row[1] not in current:
        conn.execute("DELETE FROM model WHERE id = ?", (row[0],))
        print(f'Removed stale: {row[1]}')

conn.commit()
conn.close()
```

## Always Restart
```bash
docker restart open-webui
```

## Full Diagnostic — Check Both Locations + llama-swap
```bash
echo "=== Config table ==="
docker exec open-webui python3 -c "
import sqlite3, json
conn = sqlite3.connect('/app/backend/data/webui.db')
for m in json.loads(conn.execute('SELECT data FROM config LIMIT 1').fetchone()[0])['openai']['api_configs']['0']['model_ids']: print(f'  {m}')
conn.close()
"
echo "=== Model table ==="
docker exec open-webui python3 -c "
import sqlite3
conn = sqlite3.connect('/app/backend/data/webui.db')
for r in conn.execute('SELECT id, base_model_id, name, is_active FROM model ORDER BY id'): print(f'  {r[0]:40s} active={r[1]}')
conn.close()
"
echo "=== llama-swap ==="
curl -s :9292/v1/models | python3 -c "import sys,json; [print(f'  {m[\"id\"]}') for m in json.load(sys.stdin)['data']]"
```

## Historical Notes
- **June 20, 2026:** Fleet had stale models — invisible in UI because they were missing from `config` table.
- **June 27, 2026:** Ornith added to llama-swap but invisible in UI. Root cause: missing from `model` table (not `config`). Fixed by inserting rows with admin user UUID.
