{"record":{"id":"ba98c5c827c4f01d","repo":"unslothai/unsloth","slug":"choose-only-curated-codex-models","errorCode":null,"errorMessage":"Choose only curated Codex models.","messagePattern":"Choose only curated Codex models\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/providers.py","lineNumber":112,"sourceCode":"\n\ndef _validate_provider_auth_contract(\n    info: dict,\n    *,\n    encrypted_api_key: str | None,\n    base_url: str | None,\n    models: list[str] | None,\n    updating: bool,\n    clear_api_key: bool = False,\n) -> None:\n    if info.get(\"auth_kind\") != \"chatgpt_oauth\":\n        return\n    if encrypted_api_key or clear_api_key:\n        raise HTTPException(status_code = 400, detail = \"ChatGPT subscriptions do not use API keys.\")\n    if base_url is not None and (not updating or base_url != info[\"base_url\"]):\n        raise HTTPException(status_code = 400, detail = \"ChatGPT subscription routing is fixed.\")\n    if models is not None and (not models or not set(models).issubset(set(info[\"default_models\"]))):\n        raise HTTPException(status_code = 400, detail = \"Choose only curated Codex models.\")\n\n\ndef _validate_max_output_tokens_contract(\n    provider_type: str,\n    field_was_set: bool,\n    value: Optional[int] = None,\n) -> None:\n    \"\"\"Reject a non-null override on a provider type with its own documented caps.\n\n    An explicit null is allowed through everywhere: the dialog shows the field for rows\n    it displays as Custom but the backend stores as `openai`, and a blank field\n    serialises as null, so rejecting it failed every unrelated edit of those rows.\n    Clearing an override that cannot exist is a no-op.\n    \"\"\"\n    if field_was_set and value is not None and provider_type != \"custom\":\n        raise HTTPException(\n            status_code = 400,\n            detail = \"Max Tokens limit can only be overridden for generic Custom providers.\",","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/providers.py#L94-L130","documentation":"A 400 from _validate_provider_auth_contract: for a chatgpt_oauth provider, the models list was supplied but was empty or contained at least one model outside the provider's curated default_models set. ChatGPT subscriptions expose only a fixed, curated Codex model list; arbitrary model names are rejected.","triggerScenarios":"PUT with models: [] (explicit empty list); models containing a model name not in info['default_models'] (e.g. an OpenAI API model id); syncing model lists from an OpenAI-API provider onto a subscription provider.","commonSituations":"Copy-pasting model names between provider types; UI 'select models' control submitting an empty selection instead of null; hard-coded model lists in client code.","solutions":["Send models as a subset of the provider's default_models (visible via GET /api/providers/registry or the provider row).","Send null/omit the field to keep the defaults instead of sending an empty array.","If you need a non-curated model, use an API-key-based provider type."],"exampleFix":"// before\nawait putProvider(id, { models: [] }); // -> 400\n// after\nawait putProvider(id, { models: curatedModels.filter(m => selected.has(m)) });\n// or omit `models` entirely to keep defaults","handlingStrategy":"validation","validationCode":"const allowed = new Set(info.default_models ?? []);\nconst models = requestedModels.filter(m => allowed.has(m));\nif (models.length === 0) delete body.models; // never send [] to a subscription provider\nelse body.models = models;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build the model picker options from the provider's default_models.","Distinguish 'no selection' (omit field) from 'empty list' (never send)."],"tags":["chatgpt","models","validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}