{"record":{"id":"27bf3bd687f8612e","repo":"openai/openai-python","slug":"could-not-find-header-header","errorCode":null,"errorMessage":"Could not find {header} header","messagePattern":"Could not find (.+?) header","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/openai/_utils/_utils.py","lineNumber":404,"sourceCode":"\n\ndef get_required_header(headers: HeadersLike, header: str) -> str:\n    lower_header = header.lower()\n    if is_mapping_t(headers):\n        # mypy doesn't understand the type narrowing here\n        for k, v in headers.items():  # type: ignore\n            if k.lower() == lower_header and isinstance(v, str):\n                return v\n\n    # to deal with the case where the header looks like X-Request-Id\n    intercaps_header = re.sub(r\"([^\\w])(\\w)\", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize())\n\n    for normalized_header in [header, lower_header, header.upper(), intercaps_header]:\n        value = headers.get(normalized_header)\n        if value:\n            return value\n\n    raise ValueError(f\"Could not find {header} header\")\n\n\ndef get_async_library() -> str:\n    try:\n        return sniffio.current_async_library()\n    except Exception:\n        return \"false\"\n\n\ndef lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]:\n    \"\"\"A version of functools.lru_cache that retains the type signature\n    for the wrapped function arguments.\n    \"\"\"\n    wrapper = functools.lru_cache(  # noqa: TID251\n        maxsize=maxsize,\n    )\n    return cast(Any, wrapper)  # type: ignore[no-any-return]\n","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/openai/openai-python/blob/9917c6e28e66e90e1227b3d223c06a8c5441515a/src/openai/_utils/_utils.py#L386-L422","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["If mocking, include the real headers (x-request-id, retry-after where applicable) in mocked responses","Point base_url at a backend that returns OpenAI-compatible response headers","Update proxy/gateway config to forward the relevant headers instead of stripping them","Catch ValueError around header-dependent logic if you support arbitrary backends"],"exampleFix":"# before\ndef handler(request):\n    return httpx.Response(200, json={...})  # no headers\n\n# after\ndef handler(request):\n    return httpx.Response(200, json={...}, headers={\"x-request-id\": \"req_1\"})","handlingStrategy":"try-catch","validationCode":"headers = response.headers\nif not any(headers.get(v) for v in (name, name.lower(), name.upper())):\n    skip_header_logic()","typeGuard":"def has_header(headers: object, name: str) -> bool:\n    return bool(isinstance(headers, dict) and headers.get(name)) or bool(getattr(headers, \"get\", lambda k: None)(name))","tryCatchPattern":"try:\n    rid = get_required_header(response.headers, \"x-request-id\")\nexcept ValueError:\n    rid = None","preventionTips":["Include real headers when mocking responses","Test mocks against captured real responses","Configure proxies to forward headers"],"tags":["valueerror","headers","mocking","compatibility"],"backgroundTag":"missing-response-header","analyzedSha":"9917c6e28e66e90e1227b3d223c06a8c5441515a","analyzedAt":"2026-08-28T11:46:34.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}