openai/openai-python · error · ValueError

Could not find {header} header

Error message

Could not find {header} header

What it means

get_required_header looks up a header in an httpx.Headers mapping using several casings (exact, lower, upper, intercaps). If none of the variants yields a truthy value it raises this ValueError — the expected header is entirely absent or empty. In the SDK it is used to extract response headers like x-request-id or the retry-after header during retry/error handling.

Source

Thrown at src/openai/_utils/_utils.py:404


def get_required_header(headers: HeadersLike, header: str) -> str:
    lower_header = header.lower()
    if is_mapping_t(headers):
        # mypy doesn't understand the type narrowing here
        for k, v in headers.items():  # type: ignore
            if k.lower() == lower_header and isinstance(v, str):
                return v

    # to deal with the case where the header looks like X-Request-Id
    intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize())

    for normalized_header in [header, lower_header, header.upper(), intercaps_header]:
        value = headers.get(normalized_header)
        if value:
            return value

    raise ValueError(f"Could not find {header} header")


def get_async_library() -> str:
    try:
        return sniffio.current_async_library()
    except Exception:
        return "false"


def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]:
    """A version of functools.lru_cache that retains the type signature
    for the wrapped function arguments.
    """
    wrapper = functools.lru_cache(  # noqa: TID251
        maxsize=maxsize,
    )
    return cast(Any, wrapper)  # type: ignore[no-any-return]

View on GitHub (pinned to 9917c6e28e)

Solutions

  1. If mocking, include the real headers (x-request-id, retry-after where applicable) in mocked responses
  2. Point base_url at a backend that returns OpenAI-compatible response headers
  3. Update proxy/gateway config to forward the relevant headers instead of stripping them
  4. Catch ValueError around header-dependent logic if you support arbitrary backends

Example fix

# before
def handler(request):
    return httpx.Response(200, json={...})  # no headers

# after
def handler(request):
    return httpx.Response(200, json={...}, headers={"x-request-id": "req_1"})
Defensive patterns

Strategy: try-catch

Validate before calling

headers = response.headers
if not any(headers.get(v) for v in (name, name.lower(), name.upper())):
    skip_header_logic()

Type guard

def has_header(headers: object, name: str) -> bool:
    return bool(isinstance(headers, dict) and headers.get(name)) or bool(getattr(headers, "get", lambda k: None)(name))

Try / catch

try:
    rid = get_required_header(response.headers, "x-request-id")
except ValueError:
    rid = None

Prevention

When it happens

Trigger: Responses from proxies, gateways, or test doubles (httpx.MockTransport, respx) that omit headers the SDK expects, e.g. a mocked error response missing retry-after or x-request-id; custom base_url servers not returning expected headers.

Common situations: Mocking SDK responses in tests without copying real headers; routing the SDK through corporate proxies or API gateways that strip headers; using OpenAI-compatible third-party backends that don't emit x-request-id.

Related errors


AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28). Data as JSON: /api/errors/27bf3bd687f8612e. Report an issue: GitHub.