[PR #21235] [CLOSED] fix: validate and normalize model tags to prevent UI crash #97019

Closed
opened 2026-05-15 23:25:08 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/21235
Author: @veeceey
Created: 2/7/2026
Status: Closed

Base: mainHead: fix/issue-20819-model-tags-validation


📝 Commits (1)

  • 8a909a8 fix: 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

  • 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 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


🔄 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>
GiteaMirror added the pull-request label 2026-05-15 23:25:08 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#97019