BerriAI/litellm · error · ValueError

allowed_callers must be a list of strings

Error message

allowed_callers must be a list of strings

What it means

For tools that support it (not tool-search/computer tools), a top-level 'allowed_callers' must be a list whose every element is a string. Anything else — a string, a dict, a list containing non-strings — raises this ValueError during transformation, before the API call.

Source

Thrown at litellm/llms/anthropic/chat/transformation.py:825

                    returned_tool["defer_loading"] = _defer_loading_function

        ## check if allowed_callers is set in the tool
        _allowed_callers: Final = tool.get("allowed_callers", None)
        _allowed_callers_function: Final = tool.get("function", {}).get("allowed_callers", None)
        if returned_tool is not None:
            # Only set allowed_callers on tools that support it (not tool search tools or computer tools)
            tool_type = returned_tool.get("type", "")
            if tool_type not in (
                "tool_search_tool_regex_20251119",
                "tool_search_tool_bm25_20251119",
                "computer_20241022",
                "computer_20250124",
            ):
                if _allowed_callers is not None:
                    if not isinstance(_allowed_callers, list) or not all(
                        isinstance(item, str) for item in _allowed_callers
                    ):
                        raise ValueError("allowed_callers must be a list of strings")
                    returned_tool["allowed_callers"] = _allowed_callers
                elif _allowed_callers_function is not None:
                    if not isinstance(_allowed_callers_function, list) or not all(
                        isinstance(item, str) for item in _allowed_callers_function
                    ):
                        raise ValueError("allowed_callers must be a list of strings")
                    returned_tool["allowed_callers"] = _allowed_callers_function

        ## check if input_examples is set in the tool
        _input_examples: Final = tool.get("input_examples", None)
        _input_examples_function: Final = tool.get("function", {}).get("input_examples", None)
        if returned_tool is not None:
            # Only set input_examples on user-defined tools (type "custom" or no type)
            tool_type = returned_tool.get("type", "")
            if tool_type == "custom" or (tool_type == "" and "name" in returned_tool):
                if _input_examples is not None and isinstance(_input_examples, list):
                    returned_tool["input_examples"] = _input_examples
                elif _input_examples_function is not None and isinstance(_input_examples_function, list):

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Wrap single values in a list: ['user@org'] and ensure every entry is a string.
  2. Convert numeric IDs: [str(c) for c in allowed_callers].
  3. Validate the shape at config-load time (list of str) with a JSON schema or small helper.

Example fix

# before
{"type": "custom", "name": "f", "allowed_callers": "alice"}

# after
{"type": "custom", "name": "f", "allowed_callers": ["alice"]}
Defensive patterns

Strategy: validation

Validate before calling

ac = tool.get("allowed_callers")
if isinstance(ac, str):
    tool["allowed_callers"] = [ac]
elif isinstance(ac, list):
    tool["allowed_callers"] = [str(c) for c in ac]

Type guard

def allowed_callers_ok(tool) -> bool:
    ac = tool.get("allowed_callers")
    return ac is None or (isinstance(ac, list) and all(isinstance(x, str) for x in ac))

Prevention

When it happens

Trigger: Passing allowed_callers: 'user@org' (bare string instead of list), allowed_callers: ['a', 123], or a dict of caller permissions; typical when configuring MCP-style tools with caller restrictions.

Common situations: Config files where a single value is written as a scalar instead of a one-element list; caller lists built from user IDs that are ints; merging configs that silently changes the shape.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/c58713a7a7113f49. Report an issue: GitHub.