{"record":{"id":"80427ad3189d4720","repo":"musistudio/claude-code-router","slug":"openai-resolve-retrieval-returned-no-assistant-con","errorCode":null,"errorMessage":"OpenAI resolve retrieval returned no assistant content or tool calls.","messagePattern":"OpenAI resolve retrieval returned no assistant content or tool calls\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/mcp/toolhub-mcp.ts","lineNumber":1702,"sourceCode":"      throw new Error(\"OpenAI resolve retrieval returned no assistant message.\");\n    }\n    const content = typeof message.content === \"string\" ? message.content : \"\";\n    const toolCalls = (message.tool_calls ?? [])\n      .map((toolCall, index) => {\n        const rawToolCall = toolCall as unknown as { function?: unknown };\n        const functionCall = isRecord(rawToolCall.function) ? rawToolCall.function : {};\n        return {\n          id: toolCall.id || `tool_call_${index}`,\n          type: \"function\" as const,\n          function: {\n            arguments: typeof functionCall.arguments === \"string\" ? functionCall.arguments : \"\",\n            name: typeof functionCall.name === \"string\" ? functionCall.name : \"\"\n          }\n        };\n      })\n      .filter((toolCall) => toolCall.function.name.length > 0);\n    if (!content && toolCalls.length === 0) {\n      throw new Error(\"OpenAI resolve retrieval returned no assistant content or tool calls.\");\n    }\n    return {\n      role: \"assistant\",\n      content,\n      tool_calls: toolCalls\n    };\n  }\n}\n\nasync function waitForLocalResolverEndpoint(baseURL: string, apiKey: string, timeoutMs: number): Promise<void> {\n  const readinessUrl = localResolverReadinessUrl(baseURL);\n  if (!readinessUrl) {\n    return;\n  }\n  const deadline = Date.now() + Math.min(Math.max(timeoutMs, 1000), 30_000);\n  let lastError: unknown;\n  while (Date.now() < deadline) {\n    const controller = new AbortController();","sourceCodeStart":1684,"sourceCodeEnd":1720,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/mcp/toolhub-mcp.ts#L1684-L1720","documentation":"Thrown when the resolver's assistant message exists but has neither string content nor any valid tool calls (all tool_calls with empty function names are filtered out). The model returned a structurally present but substantively empty answer.","triggerScenarios":"The chat completion returns a message with content: null/empty and tool_calls that are empty or all have blank function names.","commonSituations":"Model declining or hitting content filters; gateway stripping tool_calls; mismatch between tools parameter format and a non-OpenAI provider; edge-case finish_reason=length truncation.","solutions":["Retry once — transient empty model outputs happen","Verify tool definitions are passed in the resolve request and the endpoint supports function/tool calling","Try a different TOOLHUB_OPENAI_MODEL known to support tool calling","Shorten/simplify the query to avoid truncation or filter triggers"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for (let i = 0; i < 2; i++) {\n  try {\n    return await toolhub.resolve({ query });\n  } catch (e) {\n    if (!(e instanceof Error && e.message.includes(\"no assistant content\"))) throw e;\n  }\n}\nthrow new Error(\"Resolver returned empty responses repeatedly\");","preventionTips":["Retry once on empty model responses","Use models with reliable tool-calling"],"tags":["openai","toolhub","llm","empty-response"],"backgroundTag":"llm-empty-response-choices","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}