Fixes model tags validation so the /api/models endpoint and /api/v1/models/tags don't crash when tags are stored as plain strings (e.g., ["tag1", "tag2"]) instead of the expected [{"name": "tag1"}] format
Adds a Pydantic model_validator to ModelMeta that normalizes string tags to dict format on input
Adds defensive type checking in get_model_tags to handle both formats gracefully
Root Cause
Direct API calls to /api/v1/models/model/update can save tags in any format since there's no backend validation. When incorrectly formatted tags (plain strings) are stored, the get_model_tags endpoint crashes with AttributeError: 'str' object has no attribute 'get' because tag.get('name') fails on string objects. This causes a 500 error on the models list API, leaving the UI stuck in an infinite loading state.
Test Results
# Test 1: String tags get normalized to dict formatmeta=ModelMeta(tags=['tag1','tag2'])assertmeta.model_dump()['tags']==[{'name':'tag1'},{'name':'tag2'}]# PASS# Test 2: Dict tags pass through unchangedmeta=ModelMeta(tags=[{'name':'tag1'},{'name':'tag2'}])assertmeta.model_dump()['tags']==[{'name':'tag1'},{'name':'tag2'}]# PASS# Test 3: No tags - no crashmeta=ModelMeta()assert'tags'notinmeta.model_dump()# PASS# Test 4: Mixed/invalid tags - invalid entries skipped, strings normalizedmeta=ModelMeta(tags=['tag1',{'name':'tag2'},123])assertmeta.model_dump()['tags']==[{'name':'tag1'},{'name':'tag2'}]# PASS# Test 5: get_model_tags handles both formats without crashtags_set=set()fortagin[{'name':'a'},'b',42]:ifisinstance(tag,dict):tag_name=tag.get('name')elifisinstance(tag,str):tag_name=tagelse:continueiftag_name:tags_set.add(tag_name)assertsorted(tags_set)==['a','b']# PASS
Before fix: API call with string tags causes 500 Internal Server Error, UI shows infinite loading. After fix: String tags are auto-normalized to the correct format. Existing data with string tags is handled gracefully.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/open-webui/open-webui/pull/21235
**Author:** [@veeceey](https://github.com/veeceey)
**Created:** 2/7/2026
**Status:** ❌ Closed
**Base:** `main` ← **Head:** `fix/issue-20819-model-tags-validation`
---
### 📝 Commits (1)
- [`8a909a8`](https://github.com/open-webui/open-webui/commit/8a909a8c94a7e9cf7f4943c24afaf0c51c96a176) fix: validate model tags to prevent UI crash on malformed input
### 📊 Changes
**2 files changed** (+25 additions, -6 deletions)
<details>
<summary>View changed files</summary>
📝 `backend/open_webui/models/models.py` (+15 -2)
📝 `backend/open_webui/routers/models.py` (+10 -4)
</details>
### 📄 Description
## Summary
- Fixes model tags validation so the `/api/models` endpoint and `/api/v1/models/tags` don't crash when tags are stored as plain strings (e.g., `["tag1", "tag2"]`) instead of the expected `[{"name": "tag1"}]` format
- Adds a Pydantic `model_validator` to `ModelMeta` that normalizes string tags to dict format on input
- Adds defensive type checking in `get_model_tags` to handle both formats gracefully
## Root Cause
Direct API calls to `/api/v1/models/model/update` can save tags in any format since there's no backend validation. When incorrectly formatted tags (plain strings) are stored, the `get_model_tags` endpoint crashes with `AttributeError: 'str' object has no attribute 'get'` because `tag.get('name')` fails on string objects. This causes a 500 error on the models list API, leaving the UI stuck in an infinite loading state.
## Test Results
```python
# Test 1: String tags get normalized to dict format
meta = ModelMeta(tags=['tag1', 'tag2'])
assert meta.model_dump()['tags'] == [{'name': 'tag1'}, {'name': 'tag2'}] # PASS
# Test 2: Dict tags pass through unchanged
meta = ModelMeta(tags=[{'name': 'tag1'}, {'name': 'tag2'}])
assert meta.model_dump()['tags'] == [{'name': 'tag1'}, {'name': 'tag2'}] # PASS
# Test 3: No tags - no crash
meta = ModelMeta()
assert 'tags' not in meta.model_dump() # PASS
# Test 4: Mixed/invalid tags - invalid entries skipped, strings normalized
meta = ModelMeta(tags=['tag1', {'name': 'tag2'}, 123])
assert meta.model_dump()['tags'] == [{'name': 'tag1'}, {'name': 'tag2'}] # PASS
# Test 5: get_model_tags handles both formats without crash
tags_set = set()
for tag in [{'name': 'a'}, 'b', 42]:
if isinstance(tag, dict):
tag_name = tag.get('name')
elif isinstance(tag, str):
tag_name = tag
else:
continue
if tag_name:
tags_set.add(tag_name)
assert sorted(tags_set) == ['a', 'b'] # PASS
```
**Before fix:** API call with string tags causes 500 Internal Server Error, UI shows infinite loading.
**After fix:** String tags are auto-normalized to the correct format. Existing data with string tags is handled gracefully.
Fixes #20819
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/open-webui/open-webui/pull/21235
Author: @veeceey
Created: 2/7/2026
Status: ❌ Closed
Base:
main← Head:fix/issue-20819-model-tags-validation📝 Commits (1)
8a909a8fix: validate model tags to prevent UI crash on malformed input📊 Changes
2 files changed (+25 additions, -6 deletions)
View changed files
📝
backend/open_webui/models/models.py(+15 -2)📝
backend/open_webui/routers/models.py(+10 -4)📄 Description
Summary
/api/modelsendpoint and/api/v1/models/tagsdon't crash when tags are stored as plain strings (e.g.,["tag1", "tag2"]) instead of the expected[{"name": "tag1"}]formatmodel_validatortoModelMetathat normalizes string tags to dict format on inputget_model_tagsto handle both formats gracefullyRoot Cause
Direct API calls to
/api/v1/models/model/updatecan save tags in any format since there's no backend validation. When incorrectly formatted tags (plain strings) are stored, theget_model_tagsendpoint crashes withAttributeError: 'str' object has no attribute 'get'becausetag.get('name')fails on string objects. This causes a 500 error on the models list API, leaving the UI stuck in an infinite loading state.Test Results
Before fix: API call with string tags causes 500 Internal Server Error, UI shows infinite loading.
After fix: String tags are auto-normalized to the correct format. Existing data with string tags is handled gracefully.
Fixes #20819
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.