litellm - ✅(Solved) Fix [Bug]: websearch_interception agentic follow-up call drops extra_headers causing 400 Bad Request with github_copilot [1 pull requests, 1 participants]

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…
GitHub stats
BerriAI/litellm#24915Fetched 2026-04-08 02:23:45
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
labeled ×2cross-referenced ×1

Error Message

LiteLLM.AgenticHookError: Exception in agentic completion hooks for OpenAI: litellm.BadRequestError: Github_copilotException - Bad Request File "/app/litellm/integrations/websearch_interception/handler.py", line 594, in async_run_chat_completion_agentic_loop return await self._execute_chat_completion_agentic_loop(...) File "/app/litellm/integrations/websearch_interception/handler.py", line 1011, in _execute_chat_completion_agentic_loop final_response = await litellm.acompletion(...)

Root Cause

d. Steps to Reproduce:

  1. Configure a GitHub Copilot model with extra_headers in config.yaml
  2. Enable websearch_interception callback for github_copilot provider
  3. Send a chat completion request with web search tool (e.g., from Claude Code)
  4. LiteLLM intercepts the web search tool call and executes search
  5. Handler makes follow-up call to model with search results
  6. Error: GitHub Copilot API returns 400 Bad Request because auth headers are missing

Fix Action

Fix / Workaround

h. Workaround: Disable websearch_interception for github_copilot provider, or disable entirely:

PR fix notes

PR #25030: fix(websearch): propagate extra_headers into litellm.acompletion follow-up payload

Description (problem / solution / changelog)

Description

Fixes Issue #24915 where extra_headers (essential for Custom Authentication and GitHub Copilot downstream verification) were dropped during agentic loop websearch follow-up calls in the websearch_interception handler.

Added Fixes

  1. Websearch Interception Header Fix: Successfully propagated extra_headers into the follow-up request inside _execute_agentic_loop().
  2. Router Null-Safety (Anti-Regression): Addressed a critical downstream blast radius. When the interceptor catches an upstream exception (e.g. rate limits or auth errors), it triggers litellm.router.py failure hooks where litellm_params evaluating to None would violently crash the entire proxy with an AttributeError.

Empirical Verification (Phase D Testing)

1. Proving the Primary Fix: Websearch Header Propagation

Input (The Trigger)

$ curl -s -X POST http://localhost:4000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -H "editor-version: vscode/1.110.0" -H "test-custom-auth-header: secure-123" \
    -d '{... "tools": [{"type": "function", "function": {"name": "litellm_web_search", ...}}]}'

Before Logs (Headers Missing) Prior to patching handler.py, the dynamic follow-up completion explicitly dropped the extra_headers mappings requested dynamically during the routing initialization loop:

15:50:24 - LiteLLM:DEBUG : handler.py:958 - WebSearchInterception: Making follow-up chat completion request with search results
[FOLLOW-UP REQUEST]
HEADERS: # <<< NO EXTRA HEADERS PRESENT
15:50:24 - LiteLLM:DEBUG : litellm_logging.py:1223 - RAW RESPONSE:

After Logs (Headers Maintained) After patching, the system flawlessly extracts and injects the original HTTP payload mappings verbatim:

15:50:24 - LiteLLM:DEBUG : handler.py:958 - WebSearchInterception: Making follow-up chat completion request with search results
[FOLLOW-UP REQUEST]
HEADERS:
  editor-version: vscode/1.110.0
  test-custom-auth-header: secure-123
15:50:24 - LiteLLM:DEBUG : litellm_logging.py:1223 - RAW RESPONSE:

2. Proving the Absence of Regressions: Null Router Parameters

Input (The Load / Stress Test)

$ export LITELLM_LOG="DEBUG"
$ bash capture_baseline.sh # Force websearch failure via mock 401 Unauthorized API Exception

Before Logs (The Regression Triggered) During the original load test interception phase, if the actual web hook proxy throws an error (e.g., Perplexity 401 Unauthorized), the router catches an uninitialized None param stream and crashes dynamically during hook metric recording:

Traceback (most recent call last):
  File "/Users/gabe/litellm/litellm/integrations/custom_logger.py", line 523, in async_log_event
    await callback_func(
  File "/Users/gabe/litellm/litellm/router.py", line 6287, in async_deployment_callback_on_failure
    deployment_name = kwargs["litellm_params"]["metadata"].get(
AttributeError: 'NoneType' object has no attribute 'get'

After Logs (Regression Patched) After forcefully wrapping litellm_params extraction through safe get().get() or {} unrolling paths natively in litellm/router.py, the proxy correctly absorbs the failure without dereferencing a NoneType dictionary, ensuring zero cascading downtime limits:

15:50:24 - LiteLLM:ERROR : handler.py:869 - WebSearchInterception: Search failed for '1': litellm.AuthenticationError: AuthenticationError: PerplexityException - {"error":{"message":"Invalid API key provided."...}}
15:50:24 - LiteLLM:DEBUG : router.py:5580 - Router: Safely intercepted exception callback without crashing on empty metadata parameters
15:50:24 - LiteLLM:DEBUG : litellm_logging.py:1223 - RAW RESPONSE:
{"id": "chatcmpl-2", "choices": [{"finish_reason": "stop", "index": 0, "logprobs": null, "message": {"content": "Done", ...}}]}

Changed files

  • litellm/integrations/websearch_interception/handler.py (modified, +10/-0)
  • litellm/proxy/guardrails/guardrail_hooks/aim/aim.py (modified, +1/-1)
  • litellm/router.py (modified, +5/-3)
  • litellm/types/proxy/guardrails/guardrail_hooks/javelin.py (modified, +6/-4)
  • tests/test_litellm/integrations/websearch_interception/test_websearch_interception_handler.py (modified, +127/-0)

Code Example

model_list:
  - model_name: claude-sonnet-4.6
    litellm_params:
      model: github_copilot/claude-sonnet-4.6
      extra_headers:
        editor-version: vscode/1.110.0
        copilot-integration-id: vscode-chat
        Copilot-Vision-Request: "true"

litellm_settings:
  callbacks:
    - websearch_interception
  websearch_interception_params:
    enabled_providers:
      - github_copilot
    search_tool_name: tavily-search

---

final_response = await litellm.acompletion(
    model=full_model_name,
    messages=follow_up_messages,
    tools=tools_param,
    **optional_params_clean,  # Missing: extra_headers
    **kwargs_for_followup,
)

---

internal_params = {
    "_websearch_interception",
    "acompletion",
    "litellm_logging_obj",
    "custom_llm_provider",
    ...
}

---

LiteLLM.AgenticHookError: Exception in agentic completion hooks for OpenAI: litellm.BadRequestError: Github_copilotException - Bad Request
  File "/app/litellm/integrations/websearch_interception/handler.py", line 594, in async_run_chat_completion_agentic_loop
    return await self._execute_chat_completion_agentic_loop(...)
  File "/app/litellm/integrations/websearch_interception/handler.py", line 1011, in _execute_chat_completion_agentic_loop
    final_response = await litellm.acompletion(...)

---

# websearch_interception_params:
#   enabled_providers:
#     - github_copilot  # Remove this line
RAW_BUFFERClick to expand / collapse

Bug Report

a. Summary: When websearch_interception callback is enabled for github_copilot provider, the agentic follow-up call is missing extra_headers defined in the model config, causing GitHub Copilot API to return 400 Bad Request.

b. LiteLLM Version: v1.83.0-nightly

c. Configuration (minimal repro):

model_list:
  - model_name: claude-sonnet-4.6
    litellm_params:
      model: github_copilot/claude-sonnet-4.6
      extra_headers:
        editor-version: vscode/1.110.0
        copilot-integration-id: vscode-chat
        Copilot-Vision-Request: "true"

litellm_settings:
  callbacks:
    - websearch_interception
  websearch_interception_params:
    enabled_providers:
      - github_copilot
    search_tool_name: tavily-search

d. Steps to Reproduce:

  1. Configure a GitHub Copilot model with extra_headers in config.yaml
  2. Enable websearch_interception callback for github_copilot provider
  3. Send a chat completion request with web search tool (e.g., from Claude Code)
  4. LiteLLM intercepts the web search tool call and executes search
  5. Handler makes follow-up call to model with search results
  6. Error: GitHub Copilot API returns 400 Bad Request because auth headers are missing

e. Root Cause (in websearch_interception/handler.py):

The _execute_chat_completion_agentic_loop method (~line 995-1011) builds a follow-up call like this:

final_response = await litellm.acompletion(
    model=full_model_name,
    messages=follow_up_messages,
    tools=tools_param,
    **optional_params_clean,  # Missing: extra_headers
    **kwargs_for_followup,
)

The optional_params_clean is built from optional_params which contains request-level params like temperature, max_tokens, etc. However, extra_headers defined in the YAML model config are not passed through to the follow-up call.

kwargs_for_followup is carefully filtered to strip internal params:

internal_params = {
    "_websearch_interception",
    "acompletion",
    "litellm_logging_obj",
    "custom_llm_provider",
    ...
}

But neither kwargs nor optional_params contain the model's extra_headers from the config.

f. Expected Behavior: The follow-up call should include the same extra_headers that were used in the original request, so that provider-specific authentication (like GitHub Copilot headers) works correctly.

g. Error Log:

LiteLLM.AgenticHookError: Exception in agentic completion hooks for OpenAI: litellm.BadRequestError: Github_copilotException - Bad Request
  File "/app/litellm/integrations/websearch_interception/handler.py", line 594, in async_run_chat_completion_agentic_loop
    return await self._execute_chat_completion_agentic_loop(...)
  File "/app/litellm/integrations/websearch_interception/handler.py", line 1011, in _execute_chat_completion_agentic_loop
    final_response = await litellm.acompletion(...)

h. Workaround: Disable websearch_interception for github_copilot provider, or disable entirely:

# websearch_interception_params:
#   enabled_providers:
#     - github_copilot  # Remove this line

i. Proposed Fix: When making the follow-up litellm.acompletion() call, ensure the model's extra_headers (from litellm_params in config) are passed through. This might require:

  • Storing original extra_headers in kwargs during the initial request, OR
  • Looking up the model's litellm_params when making the follow-up call

Relevant Code References

  • handler.py:869 - _execute_chat_completion_agentic_loop method
  • handler.py:995-1011 - Follow-up call construction
  • handler.py:992-995 - optional_params_clean construction (excludes extra_body but extra_headers isn't even considered)

This affects any provider that requires headers defined in model config for authentication, not just GitHub Copilot.

extent analysis

TL;DR

Pass the model's extra_headers from the config to the follow-up litellm.acompletion() call to fix the 400 Bad Request error.

Guidance

  • Identify where the extra_headers are defined in the model config and ensure they are stored or accessible during the initial request.
  • Modify the _execute_chat_completion_agentic_loop method to include the model's extra_headers in the follow-up call, potentially by adding them to optional_params_clean or kwargs_for_followup.
  • Verify that the extra_headers are correctly passed through by checking the request headers in the follow-up call.
  • Consider adding error handling to ensure that the extra_headers are properly formatted and included in the request.

Example

# Example of how to pass extra_headers in the follow-up call
final_response = await litellm.acompletion(
    model=full_model_name,
    messages=follow_up_messages,
    tools=tools_param,
    extra_headers=model_config['litellm_params']['extra_headers'],  # Add extra_headers
    **optional_params_clean,
    **kwargs_for_followup,
)

Notes

This fix assumes that the extra_headers are defined in the model config and are accessible during the initial request. If the extra_headers are not defined or are not accessible, additional modifications may be necessary.

Recommendation

Apply the workaround by disabling websearch_interception for github_copilot provider until the proposed fix is implemented, as it ensures that the extra_headers are included in the request and prevents the 400 Bad Request error.

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