Skip to content

[Bug] Unreachable KeyError block and fragile type fallback in function_to_json #98

Description

@QiuYucheng2003
  1. Description
    During a static code review of util.py, a logical flaw was identified in the function_to_json utility function.

Inside the parameter parsing loop, the code attempts to look up type annotations using a dictionary default method, wrapped in a try...except KeyError block:
try:
param_type = type_map.get(param.annotation, "string")
except KeyError as e:
raise KeyError(...)

The Flaw: 1. Unreachable Code: The .get() method on a Python dictionary never raises a KeyError when a key is missing; it safely returns the default value ("string"). Therefore, the except KeyError block is completely dead code and will never execute.
2. Silent Type Degradation: If a function uses complex type hints (e.g., typing.List, typing.Dict, or custom objects/classes), type_map.get() will fail to match them and silently default their schema type to "string". This results in generating malformed and incorrect tool definitions for OpenAI tool calling, rather than catching the unsupported type or handling it properly.

  1. Steps To Reproduce
    Note: This issue was identified via static program analysis and code architecture review.

  2. Define a tool function with an unsupported or complex type hint (e.g., def my_tool(data: list):).

  3. Pass this function into function_to_json(my_tool).

  4. Notice that no KeyError is thrown (despite the intent in the except block), and the parameter is silently generated as {"type": "string"} instead of an actual structured JSON array/object or raising a clear exception.

  5. Expected Behavior
    If the codebase intends to throw an error for unmapped or invalid types, it should use direct dictionary access (type_map[param.annotation]) to trigger the KeyError block. Alternatively, if silent fallback is desired, the dead try...except block should be removed, and complex typing aliases should be resolved properly to prevent generating faulty JSON Schemas for the upstream LLM worker.

  6. Actual Behavior
    The except KeyError statement is dead code, and complex types silently fallback to "string", degrading the correctness of the tool definitions exported to the model.

  7. Impact
    Code Maintainability: Contains dead/misleading exception handling paths.

Functional Defect: Passing parameters with structured types yields incorrect JSON Schemas (typing complex nested arrays/objects as simple flat strings), causing tool calling execution to fail silently or hallucinate at runtime.

  1. Proposed Remediation
    If the goal is to enforce strict typing, modify the lookup to use direct indexing so the KeyError can be raised, or implement a proper typing resolver for standard typing hints:

If the intention is to raise an error for unknown types:

for param in signature.parameters.values():
try:
# Use direct lookup to allow KeyError to propagate to the except block
param_type = type_map[param.annotation]
except KeyError as e:
# Fallback gracefully or raise a meaningful exception
param_type = "string"
parameters[param.name] = {"type": param_type}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions