langchain - 💡(How to fix) Fix ChatOpenAI.with_structured_output(..., method="json_schema").stream() drops response headers / x-request-id in response_metadata

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Hi team,

We’re seeing inconsistent response header propagation when using LangChain structured output + streaming with OpenAI models.

Summary

When using:

chat_model.with_structured_output(
    SimpleAnswer,
    method="json_schema"
).stream(...)

the streamed AIMessageChunk / final message objects do not contain HTTP response headers (specifically x-request-id) inside response_metadata.

However, the same observability flow works correctly for:

non-structured streaming AzureChatOpenAI structured streaming regular create(stream=True, include_response_headers=True) paths

This makes it difficult to correlate streamed requests with provider-side logs/incidents.

Error Message

Error Message and Stack Trace (if applicable)

Root Cause

Hi team,

We’re seeing inconsistent response header propagation when using LangChain structured output + streaming with OpenAI models.

Summary

When using:

chat_model.with_structured_output(
    SimpleAnswer,
    method="json_schema"
).stream(...)

the streamed AIMessageChunk / final message objects do not contain HTTP response headers (specifically x-request-id) inside response_metadata.

However, the same observability flow works correctly for:

non-structured streaming AzureChatOpenAI structured streaming regular create(stream=True, include_response_headers=True) paths

This makes it difficult to correlate streamed requests with provider-side logs/incidents.

Fix Action

Fix / Workaround

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Code Example

from pathlib import Path
from typing import Any

from langchain_core.callbacks import BaseCallbackHandler
from langchain_openai import ChatOpenAI
from pydantic import BaseModel


class SimpleAnswer(BaseModel):
    answer: str


class HeaderCaptureHandler(BaseCallbackHandler):
    """Records whether ``x-request-id`` arrived via on_llm_end / on_llm_new_token."""

    def __init__(self) -> None:
        self.x_request_id: str | None = None

    def _grab(self, message: Any) -> None:
        if message is None:
            return
        headers = (getattr(message, 'response_metadata', None) or {}).get('headers') or {}
        rid = headers.get('x-request-id') or headers.get('X-Request-Id')
        if rid and self.x_request_id is None:
            self.x_request_id = rid

    def on_llm_new_token(self, token: str, *, chunk: Any = None, **kwargs: Any) -> None:
        self._grab(chunk)

    def on_llm_end(self, response: Any, **kwargs: Any) -> None:
        for gen_list in getattr(response, 'generations', None) or []:
            for gen in gen_list:
                self._grab(getattr(gen, 'message', None))


def run_case(label: str, runnable: Any) -> None:
    handler = HeaderCaptureHandler()
    for _ in runnable.stream('Say hello in one word.', config={'callbacks': [handler]}):
        pass
    status = handler.x_request_id or '<MISSING>'
    print(f'{label:50s} x-request-id={status}')


llm = ChatOpenAI(model='gpt-4.1-mini', streaming=True, include_response_headers=True)

run_case('A) plain streaming                              ', llm)
run_case('B) streaming + with_structured_output(json_schema)', llm.with_structured_output(SimpleAnswer, method='json_schema'))

---



---

chat_model.with_structured_output(
    SimpleAnswer,
    method="json_schema"
).stream(...)
RAW_BUFFERClick to expand / collapse

Submission checklist

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-openrouter
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

No response

Reproduction Steps / Example Code (Python)

from pathlib import Path
from typing import Any

from langchain_core.callbacks import BaseCallbackHandler
from langchain_openai import ChatOpenAI
from pydantic import BaseModel


class SimpleAnswer(BaseModel):
    answer: str


class HeaderCaptureHandler(BaseCallbackHandler):
    """Records whether ``x-request-id`` arrived via on_llm_end / on_llm_new_token."""

    def __init__(self) -> None:
        self.x_request_id: str | None = None

    def _grab(self, message: Any) -> None:
        if message is None:
            return
        headers = (getattr(message, 'response_metadata', None) or {}).get('headers') or {}
        rid = headers.get('x-request-id') or headers.get('X-Request-Id')
        if rid and self.x_request_id is None:
            self.x_request_id = rid

    def on_llm_new_token(self, token: str, *, chunk: Any = None, **kwargs: Any) -> None:
        self._grab(chunk)

    def on_llm_end(self, response: Any, **kwargs: Any) -> None:
        for gen_list in getattr(response, 'generations', None) or []:
            for gen in gen_list:
                self._grab(getattr(gen, 'message', None))


def run_case(label: str, runnable: Any) -> None:
    handler = HeaderCaptureHandler()
    for _ in runnable.stream('Say hello in one word.', config={'callbacks': [handler]}):
        pass
    status = handler.x_request_id or '<MISSING>'
    print(f'{label:50s} x-request-id={status}')


llm = ChatOpenAI(model='gpt-4.1-mini', streaming=True, include_response_headers=True)

run_case('A) plain streaming                              ', llm)
run_case('B) streaming + with_structured_output(json_schema)', llm.with_structured_output(SimpleAnswer, method='json_schema'))

Error Message and Stack Trace (if applicable)

Description

Hi team,

We’re seeing inconsistent response header propagation when using LangChain structured output + streaming with OpenAI models.

Summary

When using:

chat_model.with_structured_output(
    SimpleAnswer,
    method="json_schema"
).stream(...)

the streamed AIMessageChunk / final message objects do not contain HTTP response headers (specifically x-request-id) inside response_metadata.

However, the same observability flow works correctly for:

non-structured streaming AzureChatOpenAI structured streaming regular create(stream=True, include_response_headers=True) paths

This makes it difficult to correlate streamed requests with provider-side logs/incidents.

System Info

Package Information

langchain_core: 1.2.29 langchain: 1.2.15 langchain_community: 0.4.1 langsmith: 0.3.45 langchain_aws: 1.4.3 langchain_classic: 1.0.3 langchain_google_genai: 4.2.1 langchain_google_vertexai: 2.1.2 langchain_openai: 0.3.34 langchain_text_splitters: 1.1.1 langgraph_sdk: 0.3.13

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

langchain - 💡(How to fix) Fix ChatOpenAI.with_structured_output(..., method="json_schema").stream() drops response headers / x-request-id in response_metadata