siyuan-note/siyuan · info
capability execution was cancelled before it started
Error message
capability execution was cancelled before it started
What it means
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).
Source
Thrown at kernel/agent/tools.go:64
}
if ctx.Err() != nil {
return nil, nil, fmt.Errorf("tool execution was cancelled before it started")
}
if err := validator.ValidateInputContext(ctx, args); err != nil {
return nil, nil, fmt.Errorf("invalid tool arguments: %w", err)
}
return t, validator, nil
}
func validateCapabilityCall(ctx context.Context, registration *capabilityRegistration, args map[string]any) error {
if registration == nil {
return fmt.Errorf("capability was not exposed in this model round")
}
if !capabilityStillExecutable(registration, args) {
return fmt.Errorf("capability is disabled or no longer available: %s", registration.ID)
}
if ctx.Err() != nil {
return fmt.Errorf("capability execution was cancelled before it started")
}
if registration.Validator == nil {
return fmt.Errorf("capability validator unavailable: %s", registration.ID)
}
if err := registration.Validator.ValidateInputContext(ctx, args); err != nil {
return fmt.Errorf("invalid capability arguments: %w", err)
}
if !registration.isBrowser() &&
(registration.Tool == nil || registration.Tool.ContextHandler == nil && registration.Tool.Handler == nil) {
return fmt.Errorf("capability handler unavailable: %s", registration.ID)
}
return nil
}
// executeTool 执行单次工具调用。
func executeTool(ctx context.Context, tc openai.ToolCall, sessionID string) executedToolResult {
tool, validator := tools.LookupToolWithValidator(tc.Function.Name)
if tool == nil {View on GitHub (pinned to afa823b6b4)
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
Defensive patterns
Strategy: validation
Validate before calling
// Kernel-side: check cancellation before dispatch
if ctx.Err() != nil { return executedToolResult{Text: "cancelled", IsError: true} } Type guard
null
Try / catch
null
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- capability was not exposed in this model round
- capability is disabled or no longer available: %s
- capability validator unavailable: %s
- invalid capability arguments: %w
- capability handler unavailable: %s
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/75da117ea627de4f.
Report an issue: GitHub.