{"record":{"id":"94d5f8aa7de0259c","repo":"siyuan-note/siyuan","slug":"capability-was-not-exposed-in-this-model-round","errorCode":null,"errorMessage":"capability was not exposed in this model round","messagePattern":"capability was not exposed in this model round","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/tools.go","lineNumber":58,"sourceCode":"\tt, validator := tools.LookupToolWithValidator(toolName)\n\tif t == nil {\n\t\treturn nil, nil, fmt.Errorf(\"unknown tool: %s\", toolName)\n\t}\n\tif t.ContextHandler == nil && t.Handler == nil {\n\t\treturn nil, nil, fmt.Errorf(\"tool handler unavailable: %s\", toolName)\n\t}\n\tif ctx.Err() != nil {\n\t\treturn nil, nil, fmt.Errorf(\"tool execution was cancelled before it started\")\n\t}\n\tif err := validator.ValidateInputContext(ctx, args); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid tool arguments: %w\", err)\n\t}\n\treturn t, validator, nil\n}\n\nfunc validateCapabilityCall(ctx context.Context, registration *capabilityRegistration, args map[string]any) error {\n\tif registration == nil {\n\t\treturn fmt.Errorf(\"capability was not exposed in this model round\")\n\t}\n\tif !capabilityStillExecutable(registration, args) {\n\t\treturn fmt.Errorf(\"capability is disabled or no longer available: %s\", registration.ID)\n\t}\n\tif ctx.Err() != nil {\n\t\treturn fmt.Errorf(\"capability execution was cancelled before it started\")\n\t}\n\tif registration.Validator == nil {\n\t\treturn fmt.Errorf(\"capability validator unavailable: %s\", registration.ID)\n\t}\n\tif err := registration.Validator.ValidateInputContext(ctx, args); err != nil {\n\t\treturn fmt.Errorf(\"invalid capability arguments: %w\", err)\n\t}\n\tif !registration.isBrowser() &&\n\t\t(registration.Tool == nil || registration.Tool.ContextHandler == nil && registration.Tool.Handler == nil) {\n\t\treturn fmt.Errorf(\"capability handler unavailable: %s\", registration.ID)\n\t}\n\treturn nil","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/agent/tools.go#L40-L76","documentation":"validateCapabilityCall rejects a tool/capability invocation whose registration pointer is nil. Registration is created per model round when capabilities are exposed to the LLM; a nil registration means the model emitted a tool call for a capability that was never offered in the current round. executeCapability surfaces the message as an IsError tool result.","triggerScenarios":"The model hallucinates a tool name or replays a tool call from a previous round after the capability list was narrowed, and executeCapability is invoked with registration == nil (e.g. an MCP/plugin capability that was de-registered between rounds).","commonSituations":"Agentic loops where the tool list changes mid-conversation (user disables an MCP server mid-session), models with weak tool-calling discipline replaying stale calls, or replayed/persisted conversations resumed against a changed capability set.","solutions":["Ensure every executeCapability call site builds a non-nil capabilityRegistration (executeTool always does; check other paths)","Re-send the current capability list to the model so its next tool call references an exposed capability","Catch the IsError tool result in the agent loop and feed it back to the model as a corrective message","Check MCP/plugin tool registration logs to see why the capability was not exposed this round"],"exampleFix":"// before: calling with a possibly-nil registration\nexecuteCapability(ctx, tc, sessionID, lookupRegistration(name))\n// after: guard before invoking\nreg := lookupRegistration(name)\nif reg == nil {\n    return executedToolResult{Text: \"unknown capability: \" + name, IsError: true}\n}\nexecuteCapability(ctx, tc, sessionID, reg)","handlingStrategy":"validation","validationCode":"reg := lookupRegistration(toolName)\nif reg == nil {\n    return executedToolResult{Text: \"unknown capability: \" + toolName, IsError: true}\n}","typeGuard":"func registrationExposed(r *capabilityRegistration) bool { return r != nil }","tryCatchPattern":"if err := validateCapabilityCall(ctx, reg, args); err != nil {\n    return executedToolResult{Text: err.Error(), IsError: true}\n}","preventionTips":["Always build registrations via executeTool, which guarantees non-nil","Re-sync the exposed capability list each model round","Feed validation errors back to the model as corrective tool results"],"tags":["ai","tool-calling","agent","validation"],"backgroundTag":"unsupported-operation","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}