gastownhall/beads · error

non-retryable error: %w

Error message

non-retryable error: %w

What it means

callWithRetry distinguishes retryable failures (rate limits, transient network) from permanent ones. When isRetryable(err) is false — e.g. 401/403 auth, 400 bad request, invalid model — it records the error on the tracing span and returns immediately wrapped as "non-retryable error". Retrying the same call will fail identically.

Source

Thrown at internal/compact/haiku.go:196

				content := message.Content[0]
				if content.Type == "text" {
					return content.Text, nil
				}
				return "", fmt.Errorf("unexpected response format: not a text block (type=%s)", content.Type)
			}
			return "", fmt.Errorf("unexpected response format: no content blocks")
		}

		lastErr = err

		if ctx.Err() != nil {
			return "", ctx.Err()
		}

		if !isRetryable(err) {
			span.RecordError(err)
			span.SetStatus(codes.Error, err.Error())
			return "", fmt.Errorf("non-retryable error: %w", err)
		}
	}

	if lastErr != nil {
		span.RecordError(lastErr)
		span.SetStatus(codes.Error, lastErr.Error())
	}
	return "", fmt.Errorf("failed after %d retries: %w", h.maxRetries+1, lastErr)
}

func isRetryable(err error) bool {
	if err == nil {
		return false
	}

	if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
		return false
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped cause — fix the actual 4xx problem it names (auth, model, request size)
  2. Check that the key source matches the base URL: MINIMAX_API_KEY needs the MiniMax base URL, ANTHROPIC_API_KEY the Anthropic one
  3. Regenerate/rotate the API key if the cause is 401/403
  4. Fix the request: correct model ID, reduce payload size, validate fields
Defensive patterns

Strategy: type-guard

Validate before calling

// pre-flight: validate the key and model before calling
if !strings.HasPrefix(apiKey, "sk-ant-") && os.Getenv("MINIMAX_API_KEY") == "" {
	return errors.New("suspicious API key format; check provider/base URL pairing")
}

Type guard

func isNonRetryable(err error) bool { return err != nil && strings.Contains(err.Error(), "non-retryable error:") }

Try / catch

summary, err := client.SummarizeTier1(ctx, issue)
if isNonRetryable(err) {
	// do NOT retry; surface for human fix (key, model, request shape)
	return fmt.Errorf("permanent AI failure, manual fix needed: %w", err)
}

Prevention

When it happens

Trigger: The Anthropic API (or transport) returns an error for which isRetryable returns false during callWithRetry: invalid API key, malformed request, unknown model name, permission denied, or a non-transient 4xx.

Common situations: Expired or revoked ANTHROPIC_API_KEY; wrong model identifier after a deprecation; oversized request body; MiniMax key used against the Anthropic endpoint (or vice versa) without the matching base URL.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/ceec2da9c062282a. Report an issue: GitHub.