{"record":{"id":"0dcf9e406cf51e05","repo":"BerriAI/litellm","slug":"invalid-bearer-token","errorCode":null,"errorMessage":"Invalid bearer token","messagePattern":"Invalid bearer token","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"critical","filePath":"cookbook/mock_guardrail_server/mock_bedrock_guardrail_server.py","lineNumber":197,"sourceCode":"            detail=\"Missing Authorization header\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n\n    # Check if it's a Bearer token\n    parts = authorization.split()\n    print(f\"parts: {parts}\")\n    if len(parts) != 2 or parts[0].lower() != \"bearer\":\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Invalid Authorization header format. Expected: Bearer <token>\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n\n    token = parts[1]\n\n    # Verify token\n    if token != GUARDRAIL_CONFIG.bearer_token:\n        raise HTTPException(\n            status_code=status.HTTP_403_FORBIDDEN,\n            detail=\"Invalid bearer token\",\n        )\n\n    return token\n\n\n# ============================================================================\n# Guardrail Logic\n# ============================================================================\n\n\ndef check_blocked_words(text: str) -> Optional[WordPolicy]:\n    \"\"\"Check if text contains blocked words\"\"\"\n    found_words = []\n    text_lower = text.lower()\n\n    for word in GUARDRAIL_CONFIG.blocked_words:","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/cookbook/mock_guardrail_server/mock_bedrock_guardrail_server.py#L179-L215","documentation":"Same pre-flight guard as job creation, but on the cancel path: cancel_fine_tuning_job resolves an OpenAI client via get_openai_client(), and if it returns None (no api_key argument, no OPENAI_API_KEY env/secret, no custom client), this ValueError is raised before any API call. It signals missing credentials, not an upstream failure.","triggerScenarios":"Calling litellm.cancel_fine_tuning_job(fine_tuning_job_id=...) without api_key, client, or OPENAI_API_KEY configured anywhere in the lookup chain.","commonSituations":"Long-running training orchestration scripts that create jobs in one process (with key set) and cancel from another (cron/CI) without the env var; key rotation removing the env var between create and cancel.","solutions":["Export OPENAI_API_KEY in the environment where cancellation runs.","Or pass api_key=... explicitly to cancel_fine_tuning_job.","Or pass a constructed OpenAI client via client=."],"exampleFix":"# before\nlitellm.cancel_fine_tuning_job(fine_tuning_job_id=\"ftjob-abc\")\n\n# after\nlitellm.cancel_fine_tuning_job(fine_tuning_job_id=\"ftjob-abc\", api_key=os.environ[\"OPENAI_API_KEY\"])","handlingStrategy":"validation","validationCode":"import os\n\ndef can_cancel_jobs(api_key: str | None) -> bool:\n    return bool(api_key or os.environ.get(\"OPENAI_API_KEY\"))","typeGuard":null,"tryCatchPattern":"try:\n    litellm.cancel_fine_tuning_job(fine_tuning_job_id=jid)\nexcept ValueError as e:\n    if \"not initialized\" in str(e):\n        litellm.cancel_fine_tuning_job(fine_tuning_job_id=jid, api_key=os.environ[\"OPENAI_API_KEY\"])\n    else:\n        raise","preventionTips":["Load credentials the same way in every process touching fine-tuning (create and cancel).","Smoke-test cancel paths in CI, not just creation paths."],"tags":["openai","fine-tuning","authentication","configuration","litellm"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}