{"record":{"id":"abeb15924021e20d","repo":"unslothai/unsloth","slug":"chatgpt-subscriptions-do-not-use-api-keys","errorCode":null,"errorMessage":"ChatGPT subscriptions do not use API keys.","messagePattern":"ChatGPT subscriptions do not use API keys\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/providers.py","lineNumber":108,"sourceCode":"        max_output_tokens = row.get(\"max_output_tokens\"),\n        created_at = row[\"created_at\"],\n        updated_at = row[\"updated_at\"],\n    )\n\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    \"\"\"","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/providers.py#L90-L126","documentation":"A 400 from _validate_provider_auth_contract: the provider's auth_kind is 'chatgpt_oauth' (a ChatGPT subscription authenticated via OAuth), and the request included encrypted_api_key or set clear_api_key. ChatGPT subscription providers authenticate through OAuth tokens, not API keys, so key material in the request is a contract violation.","triggerScenarios":"POST/PUT /api/providers with provider_type whose auth_kind is chatgpt_oauth and a non-null encrypted_api_key; sending clear_api_key=true on a ChatGPT subscription row; a generic 'edit provider' form that always submits the key field.","commonSituations":"Frontend form reused between OpenAI-API and ChatGPT-subscription provider types; users pasting an OpenAI API key into a subscription provider; automated upsert code that includes every field regardless of auth kind.","solutions":["Omit encrypted_api_key and clear_api_key entirely when auth_kind is chatgpt_oauth.","If you meant to use an OpenAI API key, create a provider of an API-key type instead of the ChatGPT subscription type.","In shared form code, blank out key fields for subscription-based providers before submit."],"exampleFix":"// before\nawait putProvider(id, {\n  display_name: name,\n  encrypted_api_key: keyField, // always sent\n});\n// after\nconst body = { display_name: name };\nif (info.auth_kind !== \"chatgpt_oauth\" && keyField) {\n  body.encrypted_api_key = keyField;\n}","handlingStrategy":"validation","validationCode":"const isSubscription = (info) => info?.auth_kind === \"chatgpt_oauth\";\nif (isSubscription(info)) { delete body.encrypted_api_key; delete body.clear_api_key; }","typeGuard":"function isOAuthProvider(info: unknown): info is { auth_kind: \"chatgpt_oauth\"; default_models: string[]; base_url: string } {\n  return typeof info === \"object\" && info !== null && (info as any).auth_kind === \"chatgpt_oauth\";\n}","tryCatchPattern":null,"preventionTips":["Check auth_kind from the registry before building the request body.","Keep subscription-provider and API-key-provider forms separate."],"tags":["chatgpt","oauth","validation","providers"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}