Target branch: Verify that the pull request targets the dev branch.
Description: Provided below.
Testing: Manually tested with unit tests showing before/after behavior.
Code review: Self-reviewed.
Changelog Entry
Description
When model tags are stored as plain strings (e.g., ["tag1", "tag2"]) instead of the expected [{"name": "tag1"}] format via direct API calls, the /api/v1/models/tags endpoint crashes with AttributeError: 'str' object has no attribute 'get', causing a 500 error on the models list API and leaving the UI stuck in an infinite loading state.
Fixed
Added a Pydantic model_validator to ModelMeta that normalizes string tags to {"name": "..."} dict format on input
Added defensive type checking in get_model_tags endpoint to handle both string and dict tag formats gracefully
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 unchanged meta=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.
By submitting this pull request, I confirm that I have read and fully agree to the Contributor License Agreement (CLA), and I am providing my contributions under its terms.
🔄 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/21238
**Author:** [@veeceey](https://github.com/veeceey)
**Created:** 2/7/2026
**Status:** ❌ Closed
**Base:** `dev` ← **Head:** `fix/issue-20819-model-tags-validation`
---
### 📝 Commits (1)
- [`0bd7889`](https://github.com/open-webui/open-webui/commit/0bd7889e7ce9bc33c7f0199701b208c296624c5a) 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
# Pull Request Checklist
- [x] **Target branch:** Verify that the pull request targets the `dev` branch.
- [x] **Description:** Provided below.
- [x] **Testing:** Manually tested with unit tests showing before/after behavior.
- [x] **Code review:** Self-reviewed.
# Changelog Entry
### Description
When model tags are stored as plain strings (e.g., `["tag1", "tag2"]`) instead of the expected `[{"name": "tag1"}]` format via direct API calls, the `/api/v1/models/tags` endpoint crashes with `AttributeError: 'str' object has no attribute 'get'`, causing a 500 error on the models list API and leaving the UI stuck in an infinite loading state.
### Fixed
- Added a Pydantic `model_validator` to `ModelMeta` that normalizes string tags to `{"name": "..."}` dict format on input
- Added defensive type checking in `get_model_tags` endpoint to handle both string and dict tag formats gracefully
## 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
### Contributor License Agreement
By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms.
---
<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/21238
Author: @veeceey
Created: 2/7/2026
Status: ❌ Closed
Base:
dev← Head:fix/issue-20819-model-tags-validation📝 Commits (1)
0bd7889fix: 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
Pull Request Checklist
devbranch.Changelog Entry
Description
When model tags are stored as plain strings (e.g.,
["tag1", "tag2"]) instead of the expected[{"name": "tag1"}]format via direct API calls, the/api/v1/models/tagsendpoint crashes withAttributeError: 'str' object has no attribute 'get', causing a 500 error on the models list API and leaving the UI stuck in an infinite loading state.Fixed
model_validatortoModelMetathat normalizes string tags to{"name": "..."}dict format on inputget_model_tagsendpoint to handle both string and dict tag formats gracefullyTest 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
Contributor License Agreement
By submitting this pull request, I confirm that I have read and fully agree to the Contributor License Agreement (CLA), and I am providing my contributions under its terms.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.