{"record":{"id":"9c6fd8918293fe21","repo":"lfnovo/open-notebook","slug":"model-model-data-name-already-exists-for-provi","errorCode":null,"errorMessage":"Model '{model_data.name}' already exists for provider '{model_data.provider}' with type '{model_data.type}'","messagePattern":"Model '(.+?)' already exists for provider '(.+?)' with type '(.+?)'","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"api/routers/models.py","lineNumber":229,"sourceCode":"        if model_data.type not in valid_types:\n            raise HTTPException(\n                status_code=400,\n                detail=f\"Invalid model type. Must be one of: {valid_types}\",\n            )\n\n        # Check for duplicate model name under the same provider and type (case-insensitive)\n        from open_notebook.database.repository import repo_query\n\n        existing = await repo_query(\n            \"SELECT * FROM model WHERE string::lowercase(provider) = $provider AND string::lowercase(name) = $name AND string::lowercase(type) = $type LIMIT 1\",\n            {\n                \"provider\": model_data.provider.lower(),\n                \"name\": model_data.name.lower(),\n                \"type\": model_data.type.lower(),\n            },\n        )\n        if existing:\n            raise HTTPException(\n                status_code=400,\n                detail=f\"Model '{model_data.name}' already exists for provider '{model_data.provider}' with type '{model_data.type}'\",\n            )\n\n        new_model = Model(\n            name=model_data.name,\n            provider=model_data.provider,\n            type=model_data.type,\n            credential=model_data.credential,\n        )\n        await new_model.save()\n\n        return ModelResponse(\n            id=new_model.id or \"\",\n            name=new_model.name,\n            provider=new_model.provider,\n            type=new_model.type,\n            credential=new_model.credential,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/lfnovo/open-notebook/blob/a7de90d38aaf18ee85fd661854d35c11e44613e2/api/routers/models.py#L211-L247","documentation":"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.","triggerScenarios":"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.","commonSituations":"Double form submission, re-running a seed script, or retrying a POST that actually succeeded but the UI showed an error.","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"],"exampleFix":"// before\nPOST /models {\"name\":\"GPT-4o\",\"provider\":\"openai\",\"type\":\"language\"}\n// after\nconst existing = (await fetch('/api/v1/models').then(r=>r.json())).find(m=>m.name.toLowerCase()==='gpt-4o' && m.provider==='openai');\nif (existing) { await fetch(`/api/v1/models/${existing.id}`, {method:'PUT', ...}); } else { /* POST */ }","handlingStrategy":"validation","validationCode":"const models = await api.getModels();\nconst dup = models.find(m => m.name.toLowerCase()===data.name.toLowerCase() && m.provider===data.provider && m.type===data.type);\nif (dup) { await api.updateModel(dup.id, data); return; }","typeGuard":null,"tryCatchPattern":"try { await api.createModel(data); } catch (e) { if (e.status === 400 && /already exists/.test(e.detail)) { /* update instead or surface friendly message */ } }","preventionTips":["Check for case-insensitive duplicates before POST","Disable submit during in-flight creation","Treat provider+name+type as the unique key"],"tags":["models","duplicate","http-400"],"backgroundTag":"duplicate-resource-conflict","analyzedSha":"a7de90d38aaf18ee85fd661854d35c11e44613e2","analyzedAt":"2026-08-27T02:39:58.166Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}