{"record":{"id":"1cfb9d8fc647576e","repo":"JuliusBrussee/caveman","slug":"no-named-tools-found","errorCode":null,"errorMessage":"no named tools found","messagePattern":"no named tools found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shrink/shrink.go","lineNumber":281,"sourceCode":"\t\tobj, ok := item.(map[string]any)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\t// OpenAI nests under \"function\".\n\t\ttoolObj := obj\n\t\tif fn, ok := obj[\"function\"].(map[string]any); ok {\n\t\t\ttoolObj = fn\n\t\t}\n\t\tname, _ := toolObj[\"name\"].(string)\n\t\tif name == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\traw, _ := json.Marshal(obj)\n\t\tschema := schemaOf(toolObj)\n\t\tentries = append(entries, toolEntry{name: name, raw: raw, schema: schema})\n\t}\n\tif len(entries) == 0 {\n\t\treturn nil, fmt.Errorf(\"no named tools found\")\n\t}\n\treturn entries, nil\n}\n\n// schemaOf returns a tool's parameter schema, under either \"inputSchema\" (MCP) or\n// \"parameters\" (OpenAI).\nfunc schemaOf(tool map[string]any) map[string]any {\n\tif s, ok := tool[\"inputSchema\"].(map[string]any); ok {\n\t\treturn s\n\t}\n\tif s, ok := tool[\"parameters\"].(map[string]any); ok {\n\t\treturn s\n\t}\n\treturn nil\n}\n\n// profileOf extracts param names, per-param enums, and the required list.\nfunc profileOf(schema map[string]any) ToolProfile {","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shrink/shrink.go#L263-L299","documentation":"extractTools iterates the recognized list and keeps only entries that yield a non-empty tool name (via \"name\" or nested \"function.name\"). If none survive — the list is empty or every entry lacks a name — it reports 'no named tools found' rather than returning an empty catalog.","triggerScenarios":"Passing `{\"tools\":[]}`, an array of objects without \"name\" fields, or OpenAI entries missing the nested \"function\" object; also a single tool object whose name field is empty or misspelled (e.g. \"tool_name\").","commonSituations":"Exporting tools from a server that returned zero tools (all filtered or disabled); hand-written catalogs with a typo in the name key; responses truncated so tool objects lost their fields.","solutions":["Verify each tool entry has a \"name\" (or \"function.name\" for OpenAI shape) and fix typos","Check the upstream server actually exposes tools — connect and list tools before exporting","Lint a non-empty catalog: `{\"tools\":[{\"name\":\"search\",\"inputSchema\":{...}}]}`","Inspect the input with `jq '.tools | length'` to confirm tools exist"],"exampleFix":"// before\n{\"tools\": [{\"description\": \"search the web\"}]}\n// after\n{\"tools\": [{\"name\": \"web_search\", \"description\": \"search the web\", \"inputSchema\": {\"type\": \"object\", \"properties\": {}}}]}}","handlingStrategy":"validation","validationCode":"const tools = JSON.parse(input).tools ?? []\nconst named = tools.filter(t => typeof t?.name === 'string' && t.name.length > 0)\nif (named.length === 0) throw new Error('catalog has no named tools')","typeGuard":"function hasNamedTools(catalog: unknown): boolean {\n  const list = Array.isArray(catalog) ? catalog\n    : (catalog as any)?.tools ?? (catalog as any)?.functions ?? []\n  return list.some((t: any) => typeof t?.name === 'string' && t.name) ||\n         list.some((t: any) => typeof t?.function?.name === 'string' && t.function.name)\n}","tryCatchPattern":"tools, err := extractTools(input)\nif err != nil && err.Error() == \"no named tools found\" {\n  return fmt.Errorf(\"catalog empty or tools missing 'name' field; check upstream server\")\n}","preventionTips":["Verify the upstream server exposes tools before exporting its catalog","Use the exact 'name' (MCP) or 'function.name' (OpenAI) key in hand-written entries","Check tools length with jq before linting"],"tags":["json","validation","empty-input"],"backgroundTag":"empty-required-field","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}