{"record":{"id":"2b642bb4de211834","repo":"siyuan-note/siyuan","slug":"tool-execution-was-cancelled-before-it-started","errorCode":null,"errorMessage":"tool execution was cancelled before it started","messagePattern":"tool execution was cancelled before it started","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/agent/tools.go","lineNumber":48,"sourceCode":"\ntype executedToolResult struct {\n\tText             string\n\tModelAttachments []tools.ModelAttachment\n\tIsError          bool\n\tExecutionUnknown bool\n}\n\n// validateToolCallInput 在确认和快照之前校验工具调用，避免无效调用被误判为写操作。\nfunc validateToolCallInput(ctx context.Context, toolName string, args map[string]any) (*tools.Tool, *tools.ToolValidator, error) {\n\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 {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/agent/tools.go#L30-L66","documentation":"validateToolCallInput checks ctx.Err() before validating input or executing the tool. If the context is already cancelled or its deadline exceeded, the tool call is rejected with this static message so work never starts on a dead context.","triggerScenarios":"Any tool call issued with a context that has already been cancelled: the HTTP request was aborted, the client disconnected, the parent turn was cancelled, or the deadline expired before the call ran.","commonSituations":"Users canceling a chat turn while the model streams tool calls; long-queued requests whose timeout elapsed; background jobs reusing a request-scoped context that ended.","solutions":["Use a context not tied to an already-finished request for background tool execution","Increase the timeout budget if legitimate calls are being cancelled prematurely","Check ctx.Err() before dispatching each tool call in batch flows to skip work early","Propagate cancellation intent properly so callers can distinguish user cancel from timeout"],"exampleFix":"// before: reusing a finished request context for background work\nvalidateToolCallInput(req.Context(), toolName, args)\n// after: use a detached context with its own deadline\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nvalidateToolCallInput(ctx, toolName, args)","handlingStrategy":"type-guard","validationCode":"if ctx.Err() != nil {\n    return fmt.Errorf(\"skip tool call: context already done (%v)\", ctx.Err())\n}","typeGuard":"func ctxAlive(ctx context.Context) bool {\n    select {\n    case <-ctx.Done():\n        return false\n    default:\n        return true\n    }\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"cancelled before it started\") {\n    // benign: the caller's context ended; do not retry with the same context\n    return context.Canceled\n}","preventionTips":["Never reuse request-scoped contexts for background work","Set realistic timeouts on long tool flows","Check context liveness before dispatching each tool call"],"tags":["context","cancellation","agent","tools"],"backgroundTag":"operation-cancelled","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"}