charmbracelet/crush · info

question cancelled by user

Error message

question cancelled by user

What it means

ErrCancelled is the sentinel returned by question.Ask when the user dismisses or cancels the question instead of answering it. It lets callers distinguish deliberate cancellation from real failures.

Source

Thrown at internal/question/question.go:21

// the permission service pattern: publish a request over pubsub,
// block on a channel, and resolve when the UI sends back answers.
//
// Only one question can be pending at a time (the tool blocks until
// answered), so no correlation IDs are needed in the domain model.
package question

import (
	"context"
	"errors"
	"fmt"
	"sync"

	"github.com/charmbracelet/crush/internal/pubsub"
	"github.com/google/uuid"
)

// ErrCancelled is returned by Ask when the user cancels the question.
var ErrCancelled = errors.New("question cancelled by user")

// Type identifies the kind of question to present.
type Type string

const (
	TypeYesNo        Type = "yes_no"
	TypeSingleChoice Type = "single_choice"
	TypeMultiChoice  Type = "multi_choice"
	TypeFreeText     Type = "free_text"
)

// Choice represents a single selectable option.
type Choice struct {
	ID          string `json:"id"`
	Label       string `json:"label"`
	Description string `json:"description,omitempty"`
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check errors.Is(err, question.ErrCancelled) and treat it as a benign 'user declined' outcome.
  2. Abort the pending action without reporting an error to the user.
  3. Optionally inform the agent/user that the action was cancelled and can be retried.

Example fix

// before
ans, err := question.Ask(ctx, q)
if err != nil { return err }
// after
ans, err := question.Ask(ctx, q)
if errors.Is(err, question.ErrCancelled) {
    return errCancelledByUser // benign, no error surfaced
}
if err != nil { return err }
Defensive patterns

Strategy: try-catch

Type guard

func isUserCancelled(err error) bool {
    return errors.Is(err, question.ErrCancelled)
}

Try / catch

ans, err := question.Ask(ctx, q)
switch {
case errors.Is(err, question.ErrCancelled):
    return nil // user declined; not an error
case err != nil:
    return err
}

Prevention

When it happens

Trigger: The user presses esc/q or otherwise aborts while a yes/no or other question prompt from Ask is displayed.

Common situations: A tool run pauses to ask the user for confirmation (e.g. file edit approval) and the user cancels; an agent workflow waiting on Ask receives the sentinel and must abort the pending action gracefully.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/838d0500f3a60d7e. Report an issue: GitHub.