Skip to content

fix(client): send additional_headers from async_api - #2117

Open
anubhavlal07 wants to merge 1 commit into
langfuse:mainfrom
anubhavlal07:fix/async-api-additional-headers
Open

anubhavlal07 wants to merge 1 commit into
langfuse:mainfrom
anubhavlal07:fix/async-api-additional-headers

Conversation

@anubhavlal07

@anubhavlal07 anubhavlal07 commented Nov 9, 2026 •

Copy link
Copy Markdown

What does this PR do?

Langfuse(additional_headers=...) is documented as "Additional headers to include in all API requests", but only the sync client (langfuse.api) and the OTLP exporter receive them. LangfuseResourceManager._init_api_clients() builds AsyncLangfuseAPI without headers=, so every request made through langfuse.async_api (and helpers built on it, such as aiter_observation_pages) goes out without the configured headers. Behind a proxy or gateway that needs those headers (auth, routing, tenant headers), sync calls work and async calls fail.

Minimal repro on current main:

import asyncio
import httpx
from langfuse import Langfuse

lf = Langfuse(
    public_key="pk", secret_key="sk", base_url="https://example.com",
    additional_headers={"X-Custom-Header": "v"}, tracing_enabled=False,
)

seen = []

def handler(request):
    seen.append(request.headers.get("X-Custom-Header"))
    return httpx.Response(200, json={"status": "OK", "version": "1.0.0"})

lf.async_api._client_wrapper.httpx_client.httpx_client = httpx.AsyncClient(
    transport=httpx.MockTransport(handler)
)
asyncio.run(lf.async_api.health.health())
print(seen)

On main this prints [None]. The same call through lf.api sends the header, because the sync httpx.Client is created with headers=additional_headers.

Fix: pass headers=self.additional_headers to AsyncLangfuseAPI. The async client always builds its own httpx.AsyncClient, so the headers have nowhere else to go. Sync behaviour is unchanged, including the documented rule that a custom httpx_client keeps its own headers. The same code path runs after fork(), so re-initialised workers get the headers too.

Related, but separate: langfuse/langfuse#12422 is about a custom httpx_client not being applied to async_api. This PR only covers additional_headers, which users set without passing a custom client.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Refactor
  • Documentation update
  • Tooling, CI, or repo maintenance

Verification

uv run --frozen pytest tests/unit/test_additional_headers_simple.py
uv run --frozen ruff check langfuse/_client/resource_manager.py tests/unit/test_additional_headers_simple.py
uv run --frozen ruff format --check langfuse/_client/resource_manager.py tests/unit/test_additional_headers_simple.py
uv run --frozen mypy langfuse --no-error-summary
uv run --frozen pytest -n auto --dist worksteal tests/unit
  • New test test_async_api_sends_additional_headers sends a real async_api.health.health() request through an httpx.MockTransport and asserts that the custom header is on the wire. It fails on main and passes with the fix.
  • test_additional_headers_simple.py: 12 passed. ruff and mypy are clean.
  • Full unit suite (local Windows machine): the only failures are environment-specific and also fail without this change: symlink and time.tzset tests, a POSIX path assertion in test_serializer.py::test_path, the test_prompt_atexit subprocess tests, and the test_prompt.py fixture that needs LANGFUSE_* env vars (tests/unit/test_prompt.py fails on a fresh clone without LANGFUSE_* env vars #1976).

Checklist

  • I self-reviewed the diff using code_review.md.
  • I added or updated tests for behavior changes.
  • I updated docs, examples, or .env.template if needed. (Not needed: this change makes the code match the existing docstring.)
  • I did not hand-edit generated files; if generated files changed, I used the upstream regeneration path.
  • I did not commit secrets or credentials.

This change was prepared with the help of an AI assistant (Claude), and I reviewed and tested it.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge.

Summary

Passes additional_headers to AsyncLangfuseAPI, so async requests receive the configured headers.

  • Async API requests now include the configured additional headers.

Reviews (1) · Last reviewed commit: "fix(client): send additional_headers fro..." · Reviewed by Greptile

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@CLAassistant

CLAassistant commented Nov 9, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants