oobabooga/textgen · error · HTTPException

Unauthorized

Error message

Unauthorized

What it means

Raised by the FastAPI dependency verify_api_key (modules/api/script.py:71) on every OpenAI-compatible /v1 endpoint. When the server was started with --api-key, each request must carry an Authorization header exactly equal to 'Bearer <that key>'. If no --api-key was set at startup, the check passes silently.

Source

Thrown at modules/api/script.py:71

    ModelListResponse,
    TokenCountResponse,
    to_dict
)


async def _wait_for_disconnect(request: Request, stop_event: threading.Event):
    """Block until the client disconnects, then signal the stop_event."""
    while True:
        message = await request.receive()
        if message["type"] == "http.disconnect":
            stop_event.set()
            return


def verify_api_key(authorization: str = Header(None)) -> None:
    expected_api_key = shared.args.api_key
    if expected_api_key and (authorization is None or authorization != f"Bearer {expected_api_key}"):
        raise HTTPException(status_code=401, detail="Unauthorized")


def verify_admin_key(authorization: str = Header(None)) -> None:
    expected_api_key = shared.args.admin_key
    if expected_api_key and (authorization is None or authorization != f"Bearer {expected_api_key}"):
        raise HTTPException(status_code=401, detail="Unauthorized")


def verify_anthropic_key(x_api_key: str = Header(None, alias="x-api-key")) -> None:
    expected_api_key = shared.args.api_key
    if expected_api_key and (x_api_key is None or x_api_key != expected_api_key):
        raise HTTPException(status_code=401, detail="Unauthorized")


class AnthropicError(Exception):
    def __init__(self, message: str, error_type: str = "invalid_request_error", status_code: int = 400):
        self.message = message
        self.error_type = error_type

View on GitHub (pinned to ed888c71f2)

Solutions

  1. Send 'Authorization: Bearer <your --api-key value>' on every /v1 request (OpenAI SDK: openai.OpenAI(base_url='...:/v1', api_key='<key>')).
  2. Confirm the server was actually started with --api-key; if none is set the endpoint is open and no header is needed.
  3. Check for typos/whitespace/case in the key and remember the scheme ('Bearer ') is case-sensitive.
  4. If a reverse proxy sits in front, verify it forwards the Authorization header.

Example fix

# before
import requests
requests.post('http://127.0.0.1:5000/v1/chat/completions', json={...})  # 401

# after
requests.post(
    'http://127.0.0.1:5000/v1/chat/completions',
    headers={'Authorization': 'Bearer sk-my-key'},
    json={...},
)
Defensive patterns

Strategy: validation

Validate before calling

import os

def auth_headers(api_key: str | None) -> dict:
    if not api_key:
        raise ValueError('API key required: server was started with --api-key')
    return {'Authorization': f'Bearer {api_key}'}

Try / catch

# In OpenAI SDK clients, catch 401 explicitly and fail fast with a clear message
from openai import AuthenticationError
try:
    client.chat.completions.create(...)
except AuthenticationError:
    raise RuntimeError('Check --api-key on the server and the api_key passed to the client') from None

Prevention

When it happens

Trigger: Calling any /v1/* route (chat/completions, completions, embeddings, models, token encode/decode, etc.) with a missing Authorization header, a bare key without the 'Bearer ' prefix, the wrong key, or a malformed scheme (e.g. 'bearer' lowercase vs 'Bearer').

Common situations: Client copied an OpenAI SDK example but forgot to set api_key; key typed with whitespace/newline; using the admin key instead of the API key; server restarted with a different --api-key than the one baked into the client; proxy stripping the Authorization header.

Understand the failure class


AI-assisted analysis of oobabooga/textgen@ed888c71f2 (2026-08-15). Data as JSON: /api/errors/c87d405804eff8b8. Report an issue: GitHub.