{"record":{"id":"90a2da881e9b602b","repo":"unslothai/unsloth","slug":"max-tokens-limit-can-only-be-overridden-for-generi","errorCode":null,"errorMessage":"Max Tokens limit can only be overridden for generic Custom providers.","messagePattern":"Max Tokens limit can only be overridden for generic Custom providers\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/providers.py","lineNumber":128,"sourceCode":"        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.\",\n        )\n\n\n# ── Public key for API key encryption ─────────────────────────────\n\n\n@router.get(\"/public-key\")\nasync def get_public_key(current_subject: str = Depends(get_current_subject)):\n    \"\"\"Return the RSA public key PEM for client-side API key encryption.\n\n    ``fingerprint`` is a short SHA256 of the PEM; a mismatch with what the\n    frontend captured at encrypt time signals the keypair rotated mid-flight.\n    \"\"\"\n    return {\n        \"public_key\": get_public_key_pem(),\n        \"fingerprint\": get_public_key_fingerprint(),","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/providers.py#L110-L146","documentation":"A 400 from _validate_max_output_tokens_contract: the request explicitly set max_output_tokens to a non-null value on a provider whose provider_type is not 'custom'. Documented caps exist for built-in provider types, so an override is only meaningful for generic Custom providers; an explicit null is always allowed and clearing is a no-op.","triggerScenarios":"POST/PUT with max_output_tokens: 4096 on a provider_type like 'openai' or 'anthropic'; a dialog that serialises a blank field as a number instead of null; migration scripts copying max_output_tokens onto built-in types.","commonSituations":"Reused edit forms that always include max_output_tokens; blank-vs-null serialisation bugs in the client; users trying to raise caps on curated provider types.","solutions":["Remove max_output_tokens or send null for built-in provider types.","If you genuinely need an override, change the provider row to provider_type 'custom'.","Fix the client to distinguish 'field blank' (send null) from 'field set' (send only for custom)."],"exampleFix":"// before\nawait putProvider(id, { max_output_tokens: Number(input.value) });\n// after\nconst raw = input.value.trim();\nconst body = {};\nif (raw !== \"\" && providerType === \"custom\") {\n  body.max_output_tokens = Number(raw);\n} else {\n  body.max_output_tokens = null; // explicit clear is allowed\n}","handlingStrategy":"validation","validationCode":"function normalizeMaxTokens(providerType, raw) {\n  if (raw === \"\" || raw == null) return null; // explicit clear, always allowed\n  if (providerType !== \"custom\") return null;  // ignore for built-in types\n  return Number(raw);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only show a max-tokens input for provider_type 'custom'.","Serialise blank inputs as null, never as a number or empty string."],"tags":["validation","max-tokens","providers"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}