{"record":{"id":"c16f6f464208272f","repo":"musistudio/claude-code-router","slug":"resolve-retrieval-did-not-converge-on-any-valid-ca","errorCode":null,"errorMessage":"Resolve retrieval did not converge on any valid catalog tools after AST refinement.","messagePattern":"Resolve retrieval did not converge on any valid catalog tools after AST refinement\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/mcp/toolhub-mcp.ts","lineNumber":1616,"sourceCode":"        ? buildSearchRefinementFeedback({\n            selectedToolNames,\n            summary,\n            workflowSketch\n          })\n        : selectedToolNames.length === 0\n          ? \"Your current answer resolved to zero valid catalog tools. Call the tree-sitter tool on a revised TypeScript workflow sketch before answering.\"\n          : undefined;\n      if (refinementFeedback) {\n        messages.push(responseMessage);\n        messages.push({ role: \"user\", content: refinementFeedback });\n        continue;\n      }\n      break;\n    }\n\n    const selectedToolNames = uniqueStrings([...latestResolvedFromAnalyzer, ...llmSelectedNames]).slice(0, topK);\n    if (selectedToolNames.length === 0) {\n      throw new Error(didCallAnalyzer || analyzerCallCount > 0\n        ? \"Resolve retrieval did not converge on any valid catalog tools after AST refinement.\"\n        : \"Resolve retrieval did not converge on any valid catalog tools.\");\n    }\n    if (!didCallAnalyzer || analyzerCallCount === 0) {\n      referencedTokens = uniqueStrings([...referencedTokens, ...selectedToolNames]);\n    }\n    if (didCallAnalyzer && analyzerCallCount === 0) {\n      throw new Error(\"Resolve retrieval LLM did not complete an AST planning round.\");\n    }\n    if (!summary) {\n      summary = didCallAnalyzer\n        ? \"Resolved a planned end-to-end tool bundle with AST-assisted retrieval.\"\n        : \"Resolved a planned end-to-end tool bundle from the resolver model response.\";\n    } else if (summary.toLowerCase().includes(\"no strong tool bundle match was found\")) {\n      summary = \"Resolved a candidate tool bundle after iterative AST refinement.\";\n    }\n    return {\n      plannedSteps: plannedSteps.length > 0 ? plannedSteps : undefined,","sourceCodeStart":1598,"sourceCodeEnd":1634,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/mcp/toolhub-mcp.ts#L1598-L1634","documentation":"Thrown when the ToolHub resolve loop finished but produced zero valid catalog tool names, and at least one AST-analyzer round ran. It means the LLM resolver and the AST refinement both failed to map the query onto any tool that exists in the catalog.","triggerScenarios":"resolve() completes its retrieval loop with empty latestResolvedFromAnalyzer and llmSelectedNames after the analyzer was invoked at least once — e.g. the query is unrelated to any cataloged tool, or the LLM hallucinated tool names that don't exist.","commonSituations":"Off-topic queries; a catalog that lacks tools for the requested domain; model returning invented tool names that fail catalog validation; overly obscure phrasing the resolver can't map.","solutions":["Rephrase the query to match the domain of tools actually in the catalog","Inspect the catalog (search/list tools) to confirm relevant tools exist","Use a stronger resolver model via TOOLHUB_OPENAI_MODEL","If tools should exist, verify the ToolHub catalog ingestion/sync succeeded"],"exampleFix":"// before\nawait toolhub.resolve({ query: \"book me a dentist\" }); // catalog has only dev tools\n\n// after\nawait toolhub.resolve({ query: \"run a sql query against postgres and export to csv\" });","handlingStrategy":"fallback","validationCode":"// Pre-check the catalog has plausible candidates before resolving\nconst candidates = await toolhub.search({ query, topK: 3 });\nif (candidates.results.length === 0) {\n  return { tools: [], reason: \"no matching tools in catalog\" };\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await toolhub.resolve({ query, topK });\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"did not converge\")) {\n    return { tools: [], reason: \"no match\", query };\n  }\n  throw e;\n}","preventionTips":["Pre-filter with a cheap keyword search before LLM resolve","Surface catalog coverage gaps when converge errors cluster on one domain"],"tags":["toolhub","llm","retrieval","no-results"],"backgroundTag":"llm-no-valid-tool-match","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}