oobabooga/textgen · error · InvalidRequestError

Invalid tool specification at index {idx}.

Error message

Invalid tool specification at index {idx}.

What it means

Each entry in the 'tools' array is parsed into a pydantic ToolDefinition. If parsing raises pydantic ValidationError (wrong shape, missing required 'function.name', non-dict entries, bad parameter schema types), the server raises InvalidRequestError (400, param='tools') with the failing index, then backfills defaults (description, parameters) only for tools that passed validation.

Source

Thrown at modules/api/completions.py:1128

def validateTools(tools: list[dict]):
    # Validate each tool definition in the JSON array
    valid_tools = None
    for idx in range(len(tools)):
        tool = tools[idx]
        try:
            tool_definition = ToolDefinition(**tool)
            # Backfill defaults so Jinja2 templates don't crash on missing fields
            func = tool.get("function", {})
            if "description" not in func:
                func["description"] = ""
            if "parameters" not in func:
                func["parameters"] = {"type": "object", "properties": {}}
            if valid_tools is None:
                valid_tools = []
            valid_tools.append(tool)
        except ValidationError:
            raise InvalidRequestError(message=f"Invalid tool specification at index {idx}.", param='tools')

    return valid_tools

View on GitHub (pinned to ed888c71f2)

Solutions

  1. Use the canonical shape: {"type": "function", "function": {"name": str, "description": str (optional), "parameters": <JSON schema dict>}}.
  2. Ensure 'name' is present and a string; it is the only strictly required function field.
  3. Convert framework tool objects to plain dicts before sending (e.g. LangChain's tool.args schema inside the function key).
  4. Check the reported index in the message to find the exact broken tool entry.

Example fix

# before
tools = [{"function": {"description": "Get weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}}}}]

# after
tools = [{"type": "function", "function": {"name": "get_weather", "description": "Get weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}]
Defensive patterns

Strategy: validation

Validate before calling

def validate_tools(tools):
    for i, t in enumerate(tools):
        assert isinstance(t, dict), f'tool {i} not a dict'
        fn = t.get('function')
        assert isinstance(fn, dict) and isinstance(fn.get('name'), str) and fn['name'], f'tool {i} missing function.name'
        if 'parameters' in fn:
            assert isinstance(fn['parameters'], dict), f'tool {i} parameters must be a JSON schema object'
    return tools

Type guard

def is_valid_tool(t) -> bool:
    return (isinstance(t, dict) and isinstance(t.get('function'), dict)
            and isinstance(t['function'].get('name'), str) and len(t['function']['name']) > 0)

Try / catch

try:
    resp = client.chat.completions.create(model=m, messages=msgs, tools=tools)
except openai.BadRequestError as e:
    if 'Invalid tool specification' in str(e):
        idx = int(e.message.split('index ')[1].rstrip('.'))
        raise ValueError(f'tool[{idx}] malformed: {tools[idx]!r}')
    raise

Prevention

When it happens

Trigger: POST /v1/chat/completions with tools=["get_weather"] (bare string), tools=[{"function": {"parameters": {...}}}] (missing name), tools=[{"type": "function", "function": {"name": 42}}], or a JSON-schema 'parameters' value pydantic cannot coerce.

Common situations: Hand-written tool dicts missing the name field; passing raw Python functions or LangChain tool objects without .dict()/conversion; schema typos like 'paramters'; nested 'parameters' given as a string instead of an object.

Related errors


AI-assisted analysis of oobabooga/textgen@ed888c71f2 (2026-08-15). Data as JSON: /api/errors/3a255bc91e130436. Report an issue: GitHub.