{"record":{"id":"75da117ea627de4f","repo":"siyuan-note/siyuan","slug":"capability-execution-was-cancelled-before-it-start","errorCode":null,"errorMessage":"capability execution was cancelled before it started","messagePattern":"capability execution was cancelled before it started","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"info","filePath":"kernel/agent/tools.go","lineNumber":64,"sourceCode":"\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\n}\n\n// executeTool 执行单次工具调用。\nfunc executeTool(ctx context.Context, tc openai.ToolCall, sessionID string) executedToolResult {\n\ttool, validator := tools.LookupToolWithValidator(tc.Function.Name)\n\tif tool == nil {","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/agent/tools.go#L46-L82","documentation":"Before dispatching a capability, validateCapabilityCall checks ctx.Err() (kernel/agent/tools.go:63-65); if the turn's context is already cancelled, execution is refused with 'capability execution was cancelled before it started'. This guarantees no tool side-effects begin after the user aborted, complementing the mid-flight interruption path which instead reports an unknown-result outcome (tools.go:145-152).","triggerScenarios":"User clicks stop / closes the stream, the session hits StreamIdleTimeout (conf.AI.Agent.StreamIdleTimeout), or request cancellation propagates while tool calls are still queued — the next queued call then fails this check instead of executing.","commonSituations":"Aborting a chatty agent turn with several pending tool calls; idle-timeout firing during slow model responses; frontend navigating away mid-turn; tests cancelling contexts to clean up and observing these errors in logs.","solutions":["Treat as expected shutdown noise, not a failure — filter it from error dashboards or map to 'cancelled' status","If it appears without user aborts, review StreamIdleTimeout (default 120s, max 600s) — long tool chains can exceed it","Drain or cancel pending tool-call UI when the user stops, so the UI never waits for results already refused","Do not auto-retry: the turn is over; start a fresh turn if the user asks again"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Kernel-side: check cancellation before dispatch\nif ctx.Err() != nil { return executedToolResult{Text: \"cancelled\", IsError: true} }","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Filter this message from error dashboards — it is normal abort bookkeeping","Size StreamIdleTimeout to your longest legitimate tool chain (default 120s, max 600s)","Stop pending tool-call UI the moment the user aborts"],"tags":["agent","capability","context","cancellation"],"backgroundTag":"operation-cancelled","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}