lfnovo/open-notebook · warning · HTTPException
Model '{model_data.name}' already exists for provider '{mode
Error message
Model '{model_data.name}' already exists for provider '{model_data.provider}' with type '{model_data.type}' What it means
400 raised by POST /api/v1/models when a model with the same name already exists for the same provider and type. The duplicate check runs a case-insensitive repo_query (name, provider, type all lowercased) before creating the Model.
Source
Thrown at api/routers/models.py:229
if model_data.type not in valid_types:
raise HTTPException(
status_code=400,
detail=f"Invalid model type. Must be one of: {valid_types}",
)
# Check for duplicate model name under the same provider and type (case-insensitive)
from open_notebook.database.repository import repo_query
existing = await repo_query(
"SELECT * FROM model WHERE string::lowercase(provider) = $provider AND string::lowercase(name) = $name AND string::lowercase(type) = $type LIMIT 1",
{
"provider": model_data.provider.lower(),
"name": model_data.name.lower(),
"type": model_data.type.lower(),
},
)
if existing:
raise HTTPException(
status_code=400,
detail=f"Model '{model_data.name}' already exists for provider '{model_data.provider}' with type '{model_data.type}'",
)
new_model = Model(
name=model_data.name,
provider=model_data.provider,
type=model_data.type,
credential=model_data.credential,
)
await new_model.save()
return ModelResponse(
id=new_model.id or "",
name=new_model.name,
provider=new_model.provider,
type=new_model.type,
credential=new_model.credential,View on GitHub (pinned to a7de90d38a)
Solutions
- Use a different model name or delete/update the existing model first (DELETE /models/{id})
- GET /models first and check for case-insensitive duplicates before creating
- Make client creation idempotent by keying on provider+name+type
Example fix
// before
POST /models {"name":"GPT-4o","provider":"openai","type":"language"}
// after
const existing = (await fetch('/api/v1/models').then(r=>r.json())).find(m=>m.name.toLowerCase()==='gpt-4o' && m.provider==='openai');
if (existing) { await fetch(`/api/v1/models/${existing.id}`, {method:'PUT', ...}); } else { /* POST */ } Defensive patterns
Strategy: validation
Validate before calling
const models = await api.getModels();
const dup = models.find(m => m.name.toLowerCase()===data.name.toLowerCase() && m.provider===data.provider && m.type===data.type);
if (dup) { await api.updateModel(dup.id, data); return; } Try / catch
try { await api.createModel(data); } catch (e) { if (e.status === 400 && /already exists/.test(e.detail)) { /* update instead or surface friendly message */ } } Prevention
- Check for case-insensitive duplicates before POST
- Disable submit during in-flight creation
- Treat provider+name+type as the unique key
When it happens
Trigger: POST /models with a name that differs only by case from an existing entry (e.g. 'GPT-4o' vs 'gpt-4o') for the same provider+type; re-submitting a form after a first success.
Common situations: Double form submission, re-running a seed script, or retrying a POST that actually succeeded but the UI showed an error.
Related errors
- Invalid model type. Must be one of: {valid_types}
- {field} is required and cannot be cleared, only reassigned
- No embedding model configured. Please configure one in the M
- Item type must be either 'source' or 'note'
- Speaker profile '{value}' not found
AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27).
Data as JSON: /api/errors/9c6fd8918293fe21.
Report an issue: GitHub.