{"record":{"id":"3a255bc91e130436","repo":"oobabooga/textgen","slug":"invalid-tool-specification-at-index-idx","errorCode":null,"errorMessage":"Invalid tool specification at index {idx}.","messagePattern":"Invalid tool specification at index (.+?)\\.","errorType":"exception","errorClass":"InvalidRequestError","httpStatus":400,"severity":"error","filePath":"modules/api/completions.py","lineNumber":1128,"sourceCode":"\ndef validateTools(tools: list[dict]):\n    # Validate each tool definition in the JSON array\n    valid_tools = None\n    for idx in range(len(tools)):\n        tool = tools[idx]\n        try:\n            tool_definition = ToolDefinition(**tool)\n            # Backfill defaults so Jinja2 templates don't crash on missing fields\n            func = tool.get(\"function\", {})\n            if \"description\" not in func:\n                func[\"description\"] = \"\"\n            if \"parameters\" not in func:\n                func[\"parameters\"] = {\"type\": \"object\", \"properties\": {}}\n            if valid_tools is None:\n                valid_tools = []\n            valid_tools.append(tool)\n        except ValidationError:\n            raise InvalidRequestError(message=f\"Invalid tool specification at index {idx}.\", param='tools')\n\n    return valid_tools\n","sourceCodeStart":1110,"sourceCodeEnd":1131,"githubUrl":"https://github.com/oobabooga/textgen/blob/ed888c71f221df552750e1834b3654abab8ae345/modules/api/completions.py#L1110-L1131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use the canonical shape: {\"type\": \"function\", \"function\": {\"name\": str, \"description\": str (optional), \"parameters\": <JSON schema dict>}}.","Ensure 'name' is present and a string; it is the only strictly required function field.","Convert framework tool objects to plain dicts before sending (e.g. LangChain's tool.args schema inside the function key).","Check the reported index in the message to find the exact broken tool entry."],"exampleFix":"# before\ntools = [{\"function\": {\"description\": \"Get weather\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\"}}}}}]\n\n# after\ntools = [{\"type\": \"function\", \"function\": {\"name\": \"get_weather\", \"description\": \"Get weather\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\"}}, \"required\": [\"city\"]}}}]","handlingStrategy":"validation","validationCode":"def validate_tools(tools):\n    for i, t in enumerate(tools):\n        assert isinstance(t, dict), f'tool {i} not a dict'\n        fn = t.get('function')\n        assert isinstance(fn, dict) and isinstance(fn.get('name'), str) and fn['name'], f'tool {i} missing function.name'\n        if 'parameters' in fn:\n            assert isinstance(fn['parameters'], dict), f'tool {i} parameters must be a JSON schema object'\n    return tools","typeGuard":"def is_valid_tool(t) -> bool:\n    return (isinstance(t, dict) and isinstance(t.get('function'), dict)\n            and isinstance(t['function'].get('name'), str) and len(t['function']['name']) > 0)","tryCatchPattern":"try:\n    resp = client.chat.completions.create(model=m, messages=msgs, tools=tools)\nexcept openai.BadRequestError as e:\n    if 'Invalid tool specification' in str(e):\n        idx = int(e.message.split('index ')[1].rstrip('.'))\n        raise ValueError(f'tool[{idx}] malformed: {tools[idx]!r}')\n    raise","preventionTips":["Always emit {'type':'function','function':{'name': ...}} with a non-empty string name.","Convert framework tool objects to plain dicts before sending.","Validate the tools array client-side with a type guard before the request."],"tags":["openai-api","chat-completions","tools","pydantic","validation"],"backgroundTag":null,"analyzedSha":"ed888c71f221df552750e1834b3654abab8ae345","analyzedAt":"2026-08-15T05:24:21.000Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}