siyuan-note/siyuan · warning

tool execution was cancelled before it started

Error message

tool execution was cancelled before it started

What it means

Before validating arguments, validateToolCallInput checks ctx.Err() and aborts if the context is already cancelled or its deadline has expired. The tool call never starts; the error communicates that cancellation happened upstream so callers do not misattribute the failure to the tool itself.

Source

Thrown at kernel/agent/tools.go:48

type executedToolResult struct {
	Text             string
	ModelAttachments []tools.ModelAttachment
	IsError          bool
	ExecutionUnknown bool
}

// validateToolCallInput 在确认和快照之前校验工具调用,避免无效调用被误判为写操作。
func validateToolCallInput(ctx context.Context, toolName string, args map[string]any) (*tools.Tool, *tools.ToolValidator, error) {
	t, validator := tools.LookupToolWithValidator(toolName)
	if t == nil {
		return nil, nil, fmt.Errorf("unknown tool: %s", toolName)
	}
	if t.ContextHandler == nil && t.Handler == nil {
		return nil, nil, fmt.Errorf("tool handler unavailable: %s", toolName)
	}
	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 {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check why the context was cancelled: inspect upstream timeout/deadline settings and increase them if the budget is too small.
  2. Skip re-dispatching the tool call after cancellation; treat it as an intentional abort and let the agent round end.
  3. Ensure contexts are only cancelled after in-flight tool calls are drained during shutdown.

Example fix

// before
result, err := runAgentRound(ctx) // ctx already cancelled
// after
if ctx.Err() != nil {
    ctx = context.Background() // or create a fresh deadline-scoped ctx before the round
}
result, err := runAgentRound(ctx)
Defensive patterns

Strategy: try-catch

Validate before calling

if ctx.Err() != nil {
    return nil, fmt.Errorf("cannot dispatch tool: %w", ctx.Err())
}

Try / catch

if _, _, err := validateToolCallInput(ctx, name, args); err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { /* abort round gracefully */ }
}

Prevention

When it happens

Trigger: Executing a tool call with a context that was cancelled (ctx.CancelFunc called) or whose deadline timed out before validateToolCallInput ran — e.g. the HTTP request shut down, the session ended, or a parent deadline expired while the call was queued.

Common situations: Client disconnects mid agent run; a model round's overall timeout elapses before the tool dispatch; shutdown path cancels worker contexts while queued tool calls are processed.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2b642bb4de211834. Report an issue: GitHub.