BerriAI/litellm · critical · HTTPException
Invalid API key
Error message
Invalid API key
What it means
The client-resolution guard on the list path: list_fine_tuning_jobs resolves a client through get_openai_client(), and if none can be built (no api_key arg, no OPENAI_API_KEY env/secret, no custom client), this ValueError is raised locally before any network call. It means credentials were missing from every source in the lookup chain.
Source
Thrown at cookbook/mock_prompt_management_server/mock_prompt_management_server.py:189
Returns:
True if valid, raises HTTPException if invalid
"""
if authorization is None:
# Allow requests without authentication for testing
return True
# Extract token from "Bearer <token>"
if not authorization.startswith("Bearer "):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authorization header format. Expected 'Bearer <token>'",
)
token = authorization.replace("Bearer ", "").strip()
if token not in VALID_API_TOKENS:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid API key",
)
return True
@app.get("/beta/litellm_prompt_management", response_model=PromptResponse)
async def get_prompt(
prompt_id: str = Query(..., description="The ID of the prompt to fetch"),
project_name: Optional[str] = Query(
None, description="Optional project name filter"
),
slug: Optional[str] = Query(None, description="Optional slug filter"),
version: Optional[str] = Query(None, description="Optional version filter"),
authorization: Optional[str] = Header(None),
) -> PromptResponse:
"""View on GitHub (pinned to 6c2dcb801b)
Solutions
- Set OPENAI_API_KEY in the executing environment.
- Or pass api_key=... to list_fine_tuning_jobs.
- Or provide a prebuilt client via client=.
Example fix
# before jobs = litellm.list_fine_tuning_jobs(limit=20) # after jobs = litellm.list_fine_tuning_jobs(limit=20, api_key=os.environ["OPENAI_API_KEY"])
Defensive patterns
Strategy: validation
Validate before calling
import os, litellm
def can_list_jobs() -> bool:
return bool(os.environ.get("OPENAI_API_KEY") or litellm.api_key or litellm.openai_key) Try / catch
try:
jobs = litellm.list_fine_tuning_jobs(limit=20)
except ValueError as e:
if "not initialized" in str(e):
jobs = litellm.list_fine_tuning_jobs(limit=20, api_key=os.environ["OPENAI_API_KEY"])
else:
raise Prevention
- Dashboard/polling deployments should receive OPENAI_API_KEY via the same secret injection as the app.
- Add a boot-time credential check that fails fast.
When it happens
Trigger: Calling litellm.list_fine_tuning_jobs() (optionally with after/limit pagination) with no API key anywhere: not in the call, not in litellm module globals, not in OPENAI_API_KEY.
Common situations: Monitoring/dashboard scripts polling job lists in environments without the key; notebooks where the key was set in a different kernel; multi-tenant setups expecting router keys that are not visible to the fine-tuning handler.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Missing Authorization header
- Invalid bearer token
- Prompt '{prompt_id}' not found
- Error: {response.status_code} - {response.text}
- Invalid Authorization header format. Expected: Bearer <token
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/ad3bb719000eea0a.
Report an issue: GitHub.