charmbracelet/crush · error

agent processing failed: %w

Error message

agent processing failed: %w

What it means

After the agent stream finishes, RunNonInteractive inspects the response error. Cancellation is treated as success (returns nil), but any other error is wrapped as 'agent processing failed'. This means the agent ran but the conversation/processing stream ended with an error mid-flight (provider error, tool execution abort, stream disconnect).

Source

Thrown at internal/app/app.go:402

		_, _ = fmt.Fprintln(output)
	}()

	for {
		if progress && stderrTTY {
			// HACK: Reinitialize the terminal progress bar on every iteration
			// so it doesn't get hidden by the terminal due to inactivity.
			_, _ = fmt.Fprintf(os.Stderr, ansi.SetIndeterminateProgressBar)
		}

		select {
		case result := <-done:
			stopSpinner()
			if result.err != nil {
				if errors.Is(result.err, context.Canceled) || errors.Is(result.err, agent.ErrRequestCancelled) {
					slog.Debug("Non-interactive: agent processing cancelled", "session_id", sess.ID)
					return nil
				}
				return fmt.Errorf("agent processing failed: %w", result.err)
			}
			return nil

		case event := <-messageEvents:
			msg := event.Payload
			if msg.SessionID == sess.ID && msg.Role == message.Assistant && len(msg.Parts) > 0 {
				stopSpinner()

				content := msg.Content().String()
				readBytes := messageReadBytes[msg.ID]

				if len(content) < readBytes {
					slog.Error("Non-interactive: message content is shorter than read bytes", "message_length", len(content), "read_bytes", readBytes)
					return fmt.Errorf("message content is shorter than read bytes: %d < %d", len(content), readBytes)
				}

				part := content[readBytes:]
				// Trim leading whitespace. Sometimes the LLM includes leading

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Read the wrapped cause in logs; if it's 429/quota, wait or switch provider/model
  2. Retry the run — transient network/provider failures often resolve
  3. Check provider status page if 5xx errors repeat
  4. Reduce prompt/tool load if a specific tool consistently aborts the stream

Example fix

// before
out, err := app.RunNonInteractive(ctx, &buf, prompt, "", "", true, "", false)
// treat any error as fatal
// after
if err != nil && strings.Contains(err.Error(), "429") {
	time.Sleep(backoff) // retry transient rate limits
	out, err = app.RunNonInteractive(ctx, &buf, prompt, "", "", true, "", false)
}
Defensive patterns

Strategy: retry

Validate before calling

if !providerReachable(ctx, endpoint) { // ping provider endpoint
	return errors.New("provider endpoint unreachable")
}

Try / catch

var lastErr error
for i := 0; i < 3; i++ {
	err := app.RunNonInteractive(ctx, w, prompt, "", "", true, "", false)
	if err == nil {
		return nil
	}
	if errors.Is(err, context.Canceled) {
		return nil // intentional cancel is success in non-interactive mode
	}
	lastErr = err
	time.Sleep(backoff(i))
}
return lastErr

Prevention

When it happens

Trigger: AgentCoordinator.Run's stream completes with an error that is neither context.Canceled nor agent.ErrRequestCancelled — e.g. provider returned 4xx/5xx mid-stream, a tool call failed fatally, or the connection dropped during generation.

Common situations: API quota/rate limits hit during a long generation; provider 500s; network drop mid-stream; a shell tool command failing in a way the agent treats as fatal.

Related errors


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