{"record":{"id":"bc7ee90b5e9e5c65","repo":"sigoden/aichat","slug":"failed-to-parse-tools-i","errorCode":null,"errorMessage":"Failed to parse '.tools[{i}]'","messagePattern":"Failed to parse '\\.tools\\[(.+?)\\]'","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/serve.rs","lineNumber":931,"sourceCode":"    Ok(output)\n}\n\nfn parse_tools(tools: Option<Vec<Value>>) -> Result<Option<Vec<FunctionDeclaration>>> {\n    let tools = match tools {\n        Some(v) => v,\n        None => return Ok(None),\n    };\n    let mut functions = vec![];\n    for (i, tool) in tools.into_iter().enumerate() {\n        if let (Some(\"function\"), Some(function)) = (\n            tool[\"type\"].as_str(),\n            tool[\"function\"]\n                .as_object()\n                .and_then(|v| serde_json::from_value(json!(v)).ok()),\n        ) {\n            functions.push(function);\n        } else {\n            bail!(\"Failed to parse '.tools[{i}]'\")\n        }\n    }\n    Ok(Some(functions))\n}\n","sourceCodeStart":913,"sourceCodeEnd":936,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/serve.rs#L913-L936","documentation":"parse_tools deserializes each entry of the request's 'tools' array, expecting {type:\"function\", function:{...}}. If the entry cannot be deserialized into a FunctionDeclaration, it bails with 'Failed to parse .tools[i]', where i is the array index of the offending tool.","triggerScenarios":"POST /v1/chat/completions whose tools[i].function is missing, not an object, or lacks required fields (name/description/parameters) per the function schema.","commonSituations":"Passing tools in a non-OpenAI format (e.g. Anthropic-style tool definitions); omitting the nested 'function' object; missing 'parameters' JSON schema; typos in field names.","solutions":["Fix the tool at index i to match {type:'function', function:{name, description, parameters}}","Ensure 'parameters' is a valid JSON Schema object (use {type:'object',properties:{}} if empty)","Validate the request body against the OpenAI tools schema before sending","Update the client SDK so it emits OpenAI-format tools"],"exampleFix":"// before\n{\"tools\":[{\"name\":\"get_weather\",\"description\":\"...\"}]}\n// after\n{\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"get_weather\",\"description\":\"...\",\"parameters\":{\"type\":\"object\",\"properties\":{}}}}]}","handlingStrategy":"validation","validationCode":"function validateTools(tools) {\n  tools.forEach((t, i) => {\n    if (t?.type !== 'function' || typeof t.function?.name !== 'string' ||\n        (t.function.parameters && typeof t.function.parameters !== 'object')) {\n      throw new Error(`invalid tool at index ${i}`);\n    }\n  });\n}","typeGuard":"const isFnTool = (t) => t != null && typeof t === 'object' && t.type === 'function' && typeof t.function === 'object' && t.function !== null;","tryCatchPattern":null,"preventionTips":["Follow the OpenAI tools schema exactly (type:function + nested function object)","Always include a JSON-Schema 'parameters' object","Validate payloads against the OpenAPI schema in tests"],"tags":["openai-api","tools","schema","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}