wavetermdev/waveterm · error

anthropic %s: %s

Error message

anthropic %s: %s

What it means

parseAnthropicHTTPError converts a non-2xx HTTP response into an error. When the response body parses as Anthropic's canonical error format ({"error":{"type":...,"message":...}}) it produces "anthropic <status>: <message>", sanitized of internal hostnames. This is the highest-fidelity error path — the message is the API's own explanation.

Source

Thrown at pkg/aiusechat/anthropic/anthropic-backend.go:403

// ---------- Public entrypoint ----------
//
// Mapping rules recap (Anthropic → AI‑SDK):
// - message_start → AiMsgStart + AiMsgStartStep
// - content_block_start(type=text) → AiMsgTextStart; text_delta → AiMsgTextDelta; content_block_stop → AiMsgTextEnd
// - content_block_start(type=thinking) → AiMsgReasoningStart; thinking_delta → AiMsgReasoningDelta; stop → AiMsgReasoningEnd
// - content_block_start(type=tool_use) → AiMsgToolInputStart; input_json_delta → AiMsgToolInputDelta; stop → AiMsgToolInputAvailable
// - If final stop_reason == "tool_use": emit AiMsgFinishStep and return StopReason{Kind:ToolUse, ...} WITHOUT AiMsgFinish
// - If message_stop with stop_reason == "end_turn" or nil: emit AiMsgFinish then [DONE]
// - On Anthropic error event: AiMsgError and return StopKindError. :contentReference[oaicite:9]{index=9} :contentReference[oaicite:10]{index=10}

// parseAnthropicHTTPError parses Anthropic API HTTP error responses
func parseAnthropicHTTPError(resp *http.Response) error {
	slurp, _ := io.ReadAll(resp.Body)

	// Try to parse as Anthropic error format first
	var eresp anthropicHTTPErrorResponse
	if err := json.Unmarshal(slurp, &eresp); err == nil && eresp.Error.Message != "" {
		return sanitizeHostnameInError(fmt.Errorf("anthropic %s: %s", resp.Status, eresp.Error.Message))
	}

	// Try to parse as proxy error format
	var proxyErr uctypes.ProxyErrorResponse
	if err := json.Unmarshal(slurp, &proxyErr); err == nil && !proxyErr.Success && proxyErr.Error != "" {
		return sanitizeHostnameInError(fmt.Errorf("anthropic %s: %s", resp.Status, proxyErr.Error))
	}

	// Fall back to truncated raw response
	msg := utilfn.TruncateString(strings.TrimSpace(string(slurp)), 120)
	if msg == "" {
		msg = "unknown error"
	}
	return sanitizeHostnameInError(fmt.Errorf("anthropic %s: %s", resp.Status, msg))
}

func RunAnthropicChatStep(
	ctx context.Context,

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the message after the status code — Anthropic's error.message states the exact problem (auth, quota, model name, etc.).
  2. For 401: rotate/fix the API key in configuration.
  3. For 429: retry with exponential backoff honoring rate-limit headers (RateLimitInfo is tracked by this client).
  4. For 529/500/overloaded: retry after a delay; these are transient upstream issues.
  5. For 400: fix the request (model name, max_tokens vs thinking budget, tool schemas).

Example fix

// handling pattern
stop, _, _, err := RunAnthropicChatStep(ctx, sse, opts, cont)
if err != nil {
    var apiErr *apiError
    if strings.Contains(err.Error(), "429") {
        time.Sleep(backoff) ; retry(ctx)
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: ensure key/model are set before calling
if apiKey == "" { return errors.New("missing ANTHROPIC API key") }
if !validModelName(model) { return fmt.Errorf("unknown model %q", model) }

Try / catch

err := runAnthropic(ctx)
if err != nil {
    switch {
    case strings.Contains(err.Error(), "401"):
        return refreshAPIKey(ctx)
    case strings.Contains(err.Error(), "429"):
        return retryWithBackoff(ctx, honorRateLimitInfo)
    case strings.Contains(err.Error(), "529"), strings.Contains(err.Error(), "overloaded"):
        return retryWithBackoff(ctx, nil)
    default:
        return err
    }
}

Prevention

When it happens

Trigger: Anthropic API (or proxy acting as Anthropic) returns non-2xx with body {"error":{"message":"..."}} — e.g. 401 invalid_api_key, 400 invalid_request_error, 429 rate_limit_error, 529 overloaded_error.

Common situations: Expired/invalid API keys (401); malformed requests or unsupported model names (400); rate limits (429); Anthropic capacity outages (529/500); billing issues.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/57550dacfa273b00. Report an issue: GitHub.