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

Closed
opened 2026-05-15 23:26:19 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

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

Base: devHead: fix/issue-20819-model-tags-validation-v2


📝 Commits (2)

  • 289daf4 fix: validate model tags to prevent UI crash on malformed input
  • 32e3c7f fix: remove extra blank line to pass black formatting check

📊 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

  • Target branch: Verify that the pull request targets the dev branch.
  • Description: Provide a concise description of the changes made in this pull request down below.
  • Changelog: Ensure a changelog entry following the format of Keep a Changelog is added at the bottom of the PR description.
  • Testing: Performed manual tests to verify the implemented fix works as intended.
  • Agentic AI Code: This Pull Request has gone through additional human review AND manual testing.
  • Code review: Performed a self-review of the code.
  • Title Prefix: Prefixed with fix: to categorize this pull request.

Changelog Entry

Description

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, and adds defensive type checking in get_model_tags to handle both formats gracefully.

Supersedes #21235 (closed due to missing CLA and wrong target branch).
Fixes #20819

Changed

  • Modified backend/open_webui/models/models.py:
    • Added model_validator to ModelMeta class that normalizes string tags to dict format {"name": "tag"} on input
    • Handles mixed/invalid tag entries by filtering and normalizing them
  • Modified backend/open_webui/apps/webui/routers/models.py:
    • Added defensive type checking in get_model_tags() to handle both string and dict tag formats
    • Skips invalid tag entries gracefully

Fixed

  • Fixed AttributeError: 'str' object has no attribute 'get' crash when model tags are stored as plain strings
  • Fixed 500 Internal Server Error on /api/models endpoint that caused infinite loading state in UI
  • Fixed model tags endpoint to handle malformed data from direct API calls

Additional Information

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.

Solution Approach

Two-layer defense:

  1. Input normalization: Pydantic validator automatically converts string tags to dict format when data is saved
  2. Runtime safety: Type checking in get_model_tags handles existing malformed data gracefully

Screenshots or Videos

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.

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.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/21249 **Author:** [@veeceey](https://github.com/veeceey) **Created:** 2/8/2026 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `fix/issue-20819-model-tags-validation-v2` --- ### 📝 Commits (2) - [`289daf4`](https://github.com/open-webui/open-webui/commit/289daf42f00123f1aa0e1828a82dcb27c63aedf4) fix: validate model tags to prevent UI crash on malformed input - [`32e3c7f`](https://github.com/open-webui/open-webui/commit/32e3c7f07ac7df79b09ea258b21a61380f3e3b0a) fix: remove extra blank line to pass black formatting check ### 📊 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:** Provide a concise description of the changes made in this pull request down below. - [x] **Changelog:** Ensure a changelog entry following the format of Keep a Changelog is added at the bottom of the PR description. - [x] **Testing:** Performed manual tests to verify the implemented fix works as intended. - [x] **Agentic AI Code:** This Pull Request has gone through additional human review AND manual testing. - [x] **Code review:** Performed a self-review of the code. - [x] **Title Prefix:** Prefixed with `fix:` to categorize this pull request. # Changelog Entry ### Description 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, and adds defensive type checking in `get_model_tags` to handle both formats gracefully. Supersedes #21235 (closed due to missing CLA and wrong target branch). Fixes #20819 ### Changed - Modified `backend/open_webui/models/models.py`: - Added `model_validator` to `ModelMeta` class that normalizes string tags to dict format `{"name": "tag"}` on input - Handles mixed/invalid tag entries by filtering and normalizing them - Modified `backend/open_webui/apps/webui/routers/models.py`: - Added defensive type checking in `get_model_tags()` to handle both string and dict tag formats - Skips invalid tag entries gracefully ### Fixed - Fixed `AttributeError: 'str' object has no attribute 'get'` crash when model tags are stored as plain strings - Fixed 500 Internal Server Error on `/api/models` endpoint that caused infinite loading state in UI - Fixed model tags endpoint to handle malformed data from direct API calls --- ### Additional Information **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. **Solution Approach** Two-layer defense: 1. **Input normalization**: Pydantic validator automatically converts string tags to dict format when data is saved 2. **Runtime safety**: Type checking in `get_model_tags` handles existing malformed data gracefully ### Screenshots or Videos **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. ### 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>
GiteaMirror added the pull-request label 2026-05-15 23:26:19 -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#97031