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

  1. Treat as expected shutdown noise, not a failure — filter it from error dashboards or map to 'cancelled' status
  2. If it appears without user aborts, review StreamIdleTimeout (default 120s, max 600s) — long tool chains can exceed it
  3. Drain or cancel pending tool-call UI when the user stops, so the UI never waits for results already refused
  4. 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

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


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/75da117ea627de4f. Report an issue: GitHub.