Skip to content

fix(mypy): resolve missing return statements and type casting issues#20618

Merged
ishaan-jaff merged 2 commits intomainfrom
litellm_fix_mypy_regression_57774
Feb 7, 2026
Merged

fix(mypy): resolve missing return statements and type casting issues#20618
ishaan-jaff merged 2 commits intomainfrom
litellm_fix_mypy_regression_57774

Conversation

@shin-bot-litellm
Copy link
Collaborator

Mypy Regression Fix

Pipeline: #57774

Fixes

  1. handler.py - Add explicit raise for unexpected response types (missing return statement)
  2. token_counter.py - Cast dict values to str before passing to count_function
  3. pangea.py - Add type cast for messages assignment

Testing

  • Run python -m mypy litellm/responses/litellm_completion_transformation/handler.py litellm/litellm_core_utils/token_counter.py litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py --ignore-missing-imports to verify

@vercel
Copy link

vercel bot commented Feb 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Feb 7, 2026 1:47am

Request Review

@CLAassistant
Copy link

CLAassistant commented Feb 7, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
0 out of 2 committers have signed the CLA.

❌ Shin
❌ shin-bot-litellm


Shin seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 7, 2026

Greptile Overview

Greptile Summary

  • Fixes mypy regressions by making response handlers exhaustively return/raise, and by casting content/message values to satisfy token counter and guardrail hook typing.
  • handler.py now raises on unexpected completion response types in both sync and async paths to close a missing-return branch.
  • token_counter.py now coerces text and thinking block values to str before passing to TokenCounterFunction.
  • pangea.py adds a cast() for data["messages"] when building the Pangea payload, but this change should be reviewed for runtime correctness (see comment).

Confidence Score: 4/5

  • Mostly safe to merge, but one guardrail hook path should be corrected to avoid sending invalid payloads at runtime.
  • The mypy-driven changes in handler.py and token_counter.py are straightforward and unlikely to change behavior in normal cases. The pangea.py cast fixes typing but may allow None messages to reach the Pangea API and has overlapping branching around response types; that needs adjustment before merging.
  • litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py

Important Files Changed

Filename Overview
litellm/litellm_core_utils/token_counter.py Casts text/thinking content block values to str before token counting to satisfy TokenCounterFunction typing; behavior change is minimal (non-str values now count as their string representation).
litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py Adds typing imports and cast() for data.get("messages") in post-call hook; current logic can pass None as messages and has branch overlap around TextCompletionResponse vs ModelResponse.
litellm/responses/litellm_completion_transformation/handler.py Adds explicit raise ValueError in sync/async response handlers to satisfy mypy 'missing return' by handling unexpected completion response types.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Handler as LiteLLMCompletionTransformationHandler
    participant LiteLLM as litellm
    participant Transform as LiteLLMCompletionResponsesConfig
    participant StreamIter as LiteLLMCompletionStreamingIterator
    participant Pangea as PangeaHandler

    Caller->>Handler: response_api_handler(...)
    Handler->>Transform: transform_responses_api_request_to_chat_completion_request(...)
    alt _is_async
        Handler->>Handler: async_response_api_handler(...)
        Handler->>LiteLLM: acompletion(**args)
    else sync
        Handler->>LiteLLM: completion(**args)
    end

    alt ModelResponse
        Handler->>Transform: transform_chat_completion_response_to_responses_api_response(...)
        Handler-->>Caller: ResponsesAPIResponse
    else CustomStreamWrapper
        Handler->>StreamIter: new StreamingIterator(...)
        Handler-->>Caller: Streaming iterator
    else Unexpected type
        Handler-->>Caller: raise ValueError
    end

    Note over Pangea: In proxy guardrails, post_call hook
    Caller->>Pangea: async_post_call_success_hook(data, response)
    Pangea->>Pangea: _async_post_call_success_hook(...)
    alt response is TextCompletionResponse
        Pangea->>Pangea: input_messages = _TextCompletionRequest(data).get_messages()
    end
    alt response is ModelResponse
        Pangea->>Pangea: input_messages = cast(List[Dict[Any,Any]], data.get("messages"))
        Pangea->>Pangea: _call_pangea_ai_guard("v1beta/guard", payload)
    else not ModelResponse
        Pangea-->>Caller: return
    end

Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 7, 2026

Additional Comments (1)

litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py
Possible UnboundLocalError
In _async_post_call_success_hook, input_messages can be undefined when response is a ModelResponse but not a TextCompletionResponse: the first if isinstance(response, TextCompletionResponse): ... doesn’t elif, so execution continues, then else: input_messages = cast(... data.get("messages")) runs; but if response is TextCompletionResponse and also ModelResponse (depending on type hierarchy), input_messages gets overwritten with data.get("messages") and the _TextCompletionRequest branch is ignored. More importantly, if response is TextCompletionResponse and not ModelResponse, the function returns at line 254 and input_messages is fine; but if response is ModelResponse and data.get("messages") is None, the cast doesn’t prevent None from flowing into the payload and Pangea API call. Consider making the branches mutually exclusive (elif) and ensuring input_messages is always a list before using it (or fallback to _TextCompletionRequest).

…ssages

Address Greptile review feedback:
- Make branches mutually exclusive using elif to prevent input_messages from being overwritten
- Handle case where data.get('messages') returns None to avoid passing invalid payload to Pangea API
@shin-bot-litellm
Copy link
Collaborator Author

@greptile can you review again

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 7, 2026

Greptile Overview

Greptile Summary

Fixed three mypy type checking issues to ensure clean static type analysis:

  • handler.py: Added explicit ValueError raises after if-elif chains in both sync and async response handlers to ensure all code paths either return or raise
  • token_counter.py: Added str() casts around c.get("text") and c.get("thinking") calls to guarantee string type for the count_function parameter
  • pangea.py: Refactored nested if-not-isinstance pattern to cleaner if-elif-else structure with explicit cast() for messages assignment, improving both type safety and code clarity

All changes are defensive type safety improvements with no behavioral changes to the runtime logic.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk - purely defensive type safety improvements
  • All changes are focused solely on satisfying mypy type checking without altering runtime behavior. The fixes are defensive (explicit raises, type casts) and follow Python best practices. No logic changes, no new features, no performance implications.
  • No files require special attention

Important Files Changed

Filename Overview
litellm/responses/litellm_completion_transformation/handler.py Added explicit raise statements after if-elif chains to satisfy mypy type checking for return statements in both sync and async handlers
litellm/litellm_core_utils/token_counter.py Added str() casts for text and thinking content blocks to ensure count_function receives string type as expected
litellm/proxy/guardrails/guardrail_hooks/pangea/pangea.py Refactored control flow from nested if-not-isinstance to if-elif-else structure with explicit type cast for messages, improving type safety and clarity

Sequence Diagram

sequenceDiagram
    participant MyPy as MyPy Type Checker
    participant Handler as handler.py
    participant TokenCounter as token_counter.py
    participant Pangea as pangea.py
    
    Note over MyPy,Pangea: Mypy Type Checking Issues
    
    MyPy->>Handler: Check return paths in response_api_handler()
    Handler-->>MyPy: Error: Not all code paths return a value
    Note over Handler: Fixed: Added raise after if-elif chain
    
    MyPy->>TokenCounter: Check _count_content_list() types
    TokenCounter-->>MyPy: Error: c.get() may not return str type
    Note over TokenCounter: Fixed: Cast c.get("text") and c.get("thinking") to str
    
    MyPy->>Pangea: Check _async_post_call_success_hook() types
    Pangea-->>MyPy: Error: messages type not explicitly cast
    Note over Pangea: Fixed: Refactored to if-elif-else with cast()
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@ishaan-jaff ishaan-jaff merged commit 29990c8 into main Feb 7, 2026
11 of 13 checks passed
krrishdholakia added a commit that referenced this pull request Feb 7, 2026
…ng format for Claude Code (#20631)

* Add http support to custom code guardrails + Unified guardrails for MCP + Agent guardrail support (#20619)

* fix: fix styling

* fix(custom_code_guardrail.py): add http support for custom code guardrails

allows users to call external guardrails on litellm with minimal code changes (no custom handlers)

Test guardrail integrations more easily

* feat(a2a/): add guardrails for agent interactions

allows the same guardrails for llm's to be applied to agents as well

* fix(a2a/): support passing guardrails to a2a from the UI

* style(code-editor): allow editing custom code guardrails on ui + add examples of pre/post calls for custom code guardrails

* feat(mcp/): support custom code guardrails for mcp calls

allows custom code guardrails to work on mcp input

* feat(chatui.tsx): support guardrails on mcp tool calls on playground

* fix(mypy): resolve missing return statements and type casting issues (#20618)

* fix(mypy): resolve missing return statements and type casting issues

* fix(pangea): use elif to prevent UnboundLocalError and handle None messages

Address Greptile review feedback:
- Make branches mutually exclusive using elif to prevent input_messages from being overwritten
- Handle case where data.get('messages') returns None to avoid passing invalid payload to Pangea API

---------

Co-authored-by: Shin <shin@openclaw.ai>

* [Feat] MCP Gateway - Allow setting MCP Servers as Private/Public available on Internet (#20607)

* update MCPAuthenticatedUser

* add available_on_public_internet for MCPs

* update claude.md

* init IPAddressUtils

* init available_on_public_internet

* add on REST endpoints

* filter with IP

* TestIsInternalIp

* _extract_mcp_headers_from_request

* init get_mcp_client_ip

* _get_general_settings

* allowed_server_ids

* address PR comments

* get_mcp_server_by_name fix

* fix server

* fix review comments

* get_public_mcp_servers

* address _get_allowed_mcp_servers

* fixing user_id

* [Feat] IP-Based Access Control for MCP Servers (#20620)

* update MCPAuthenticatedUser

* add available_on_public_internet for MCPs

* update claude.md

* init IPAddressUtils

* init available_on_public_internet

* add on REST endpoints

* filter with IP

* TestIsInternalIp

* _extract_mcp_headers_from_request

* init get_mcp_client_ip

* _get_general_settings

* allowed_server_ids

* address PR comments

* get_mcp_server_by_name fix

* fix server

* fix review comments

* get_public_mcp_servers

* address _get_allowed_mcp_servers

* test fix

* fix linting

* inint ui types

* add ui for managing MCP private/public

* add ui

* fixes

* add to schema

* add types

* fix endpoint

* add endpoint

* update manager

* test mcp

* dont use external party for ip address

* Add OpenAI/Azure release test suite with HTTP client lifecycle regression detection (#20622)

* docs (#20626)

* docs

* fix(mypy): resolve type checking errors in 5 files (#20627)

- a2a_protocol/exception_mapping_utils.py: Fix type ignore comment for None assignment
- caching/redis_cache.py: Add type ignore for async ping return type
- caching/redis_cluster_cache.py: Add type ignore for async ping return type
- llms/deprecated_providers/palm.py: Add type ignore for palm.generate_text
- proxy/auth/handle_jwt.py: Add type ignore for jwt.decode options argument

All changes add appropriate type: ignore comments to handle library typing inconsistencies.

* fix(test): update deprecated gemini embedding model (#20621)

Replace text-embedding-004 with gemini-embedding-001.

The old model was deprecated and returns 404:
'models/text-embedding-004 is not found for API version v1beta'

Co-authored-by: Shin <shin@openclaw.ai>

* ui new buil

* fix(websearch_interception): convert agentic loop response to streaming format when original request was streaming

Fixes #20187 - When using websearch_interception in Bedrock with Claude Code:
1. Output tokens were showing as 0 because the agentic loop response wasn't
   being converted back to streaming format
2. The response from the agentic loop (follow-up request) was returned as a
   non-streaming dict, but Claude Code expects a streaming response

This fix adds streaming format conversion for the agentic loop response when
the original request was streaming (detected via the
websearch_interception_converted_stream flag in logging_obj).

The fix ensures:
- Output tokens are correctly included in the message_delta event
- stop_reason is properly preserved
- The response format matches what Claude Code expects

---------

Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
Co-authored-by: Shin <shin@openclaw.ai>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
krrishdholakia added a commit that referenced this pull request Feb 7, 2026
…iohttp tracing (#20630)

* Add http support to custom code guardrails + Unified guardrails for MCP + Agent guardrail support (#20619)

* fix: fix styling

* fix(custom_code_guardrail.py): add http support for custom code guardrails

allows users to call external guardrails on litellm with minimal code changes (no custom handlers)

Test guardrail integrations more easily

* feat(a2a/): add guardrails for agent interactions

allows the same guardrails for llm's to be applied to agents as well

* fix(a2a/): support passing guardrails to a2a from the UI

* style(code-editor): allow editing custom code guardrails on ui + add examples of pre/post calls for custom code guardrails

* feat(mcp/): support custom code guardrails for mcp calls

allows custom code guardrails to work on mcp input

* feat(chatui.tsx): support guardrails on mcp tool calls on playground

* fix(mypy): resolve missing return statements and type casting issues (#20618)

* fix(mypy): resolve missing return statements and type casting issues

* fix(pangea): use elif to prevent UnboundLocalError and handle None messages

Address Greptile review feedback:
- Make branches mutually exclusive using elif to prevent input_messages from being overwritten
- Handle case where data.get('messages') returns None to avoid passing invalid payload to Pangea API

---------

Co-authored-by: Shin <shin@openclaw.ai>

* [Feat] MCP Gateway - Allow setting MCP Servers as Private/Public available on Internet (#20607)

* update MCPAuthenticatedUser

* add available_on_public_internet for MCPs

* update claude.md

* init IPAddressUtils

* init available_on_public_internet

* add on REST endpoints

* filter with IP

* TestIsInternalIp

* _extract_mcp_headers_from_request

* init get_mcp_client_ip

* _get_general_settings

* allowed_server_ids

* address PR comments

* get_mcp_server_by_name fix

* fix server

* fix review comments

* get_public_mcp_servers

* address _get_allowed_mcp_servers

* fixing user_id

* [Feat] IP-Based Access Control for MCP Servers (#20620)

* update MCPAuthenticatedUser

* add available_on_public_internet for MCPs

* update claude.md

* init IPAddressUtils

* init available_on_public_internet

* add on REST endpoints

* filter with IP

* TestIsInternalIp

* _extract_mcp_headers_from_request

* init get_mcp_client_ip

* _get_general_settings

* allowed_server_ids

* address PR comments

* get_mcp_server_by_name fix

* fix server

* fix review comments

* get_public_mcp_servers

* address _get_allowed_mcp_servers

* test fix

* fix linting

* inint ui types

* add ui for managing MCP private/public

* add ui

* fixes

* add to schema

* add types

* fix endpoint

* add endpoint

* update manager

* test mcp

* dont use external party for ip address

* Add OpenAI/Azure release test suite with HTTP client lifecycle regression detection (#20622)

* docs (#20626)

* docs

* fix(mypy): resolve type checking errors in 5 files (#20627)

- a2a_protocol/exception_mapping_utils.py: Fix type ignore comment for None assignment
- caching/redis_cache.py: Add type ignore for async ping return type
- caching/redis_cluster_cache.py: Add type ignore for async ping return type
- llms/deprecated_providers/palm.py: Add type ignore for palm.generate_text
- proxy/auth/handle_jwt.py: Add type ignore for jwt.decode options argument

All changes add appropriate type: ignore comments to handle library typing inconsistencies.

* fix(test): update deprecated gemini embedding model (#20621)

Replace text-embedding-004 with gemini-embedding-001.

The old model was deprecated and returns 404:
'models/text-embedding-004 is not found for API version v1beta'

Co-authored-by: Shin <shin@openclaw.ai>

* ui new buil

* fix(http_handler): bypass cache when shared_session is provided for aiohttp tracing

When users pass a shared_session with trace_configs to acompletion(),
the get_async_httpx_client() function was ignoring it and returning
a cached client without the user's tracing configuration.

This fix bypasses the cache when shared_session is provided, ensuring
the user's ClientSession (with its trace_configs, connector settings, etc.)
is actually used for the request.

Fixes #20174

---------

Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
Co-authored-by: Shin <shin@openclaw.ai>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com>
Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com>
Co-authored-by: shin-bot-litellm <shin-bot-litellm@users.noreply.github.com>
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.

3 participants