wavetermdev/waveterm · error
openai %s: %s
Error message
openai %s: %s
What it means
This error surfaces when the OpenAI API returns an HTTP error whose body successfully parsed as the standard OpenAI error envelope ({"error":{"message":...}}). The message is 'openai <status>: <api error message>'. It is the library's way of forwarding the API's own error text alongside the HTTP status.
Source
Thrown at pkg/aiusechat/openai/openai-backend.go:592
decoder := eventsource.NewDecoder(resp.Body)
stopReason, rtnMessages := handleOpenAIStreamingResp(ctx, sse, decoder, cont, chatOpts)
return stopReason, rtnMessages, rateLimitInfo, nil
}
// parseOpenAIHTTPError parses OpenAI API HTTP error responses
func parseOpenAIHTTPError(resp *http.Response) error {
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("openai %s: failed to read error response: %v", resp.Status, err)
}
logutil.DevPrintf("openai full error: %s\n", body)
// Try to parse as OpenAI error format first
var errorResp openAIErrorResponse
if err := json.Unmarshal(body, &errorResp); err == nil && errorResp.Error.Message != "" {
return fmt.Errorf("openai %s: %s", resp.Status, errorResp.Error.Message)
}
// Try to parse as proxy error format
var proxyErr uctypes.ProxyErrorResponse
if err := json.Unmarshal(body, &proxyErr); err == nil && !proxyErr.Success && proxyErr.Error != "" {
return fmt.Errorf("openai %s: %s", resp.Status, proxyErr.Error)
}
return fmt.Errorf("openai %s: %s", resp.Status, utilfn.TruncateString(string(body), 120))
}
// handleOpenAIStreamingResp handles the OpenAI SSE streaming response
func handleOpenAIStreamingResp(ctx context.Context, sse *sse.SSEHandlerCh, decoder *eventsource.Decoder, cont *uctypes.WaveContinueResponse, chatOpts uctypes.WaveChatOpts) (*uctypes.WaveStopReason, []*OpenAIChatMessage) {
// Per-response state
state := &openaiStreamingState{
blockMap: map[string]*openaiBlockState{},
chatOpts: chatOpts,
}View on GitHub (pinned to a4447c1563)
Solutions
- Read the API error text after 'openai <status>:' and act on it (401 -> fix key, 429 -> backoff, 404 -> fix model name)
- Verify the API key is valid and has quota for the requested model
- Implement exponential backoff on 429 responses
- Confirm the configured base URL matches the provider (api.openai.com vs Azure/compatible proxy)
Example fix
// before
client.SetAPIKey("") // stale/empty key -> 401 -> openai 401: Incorrect API key provided
// after
client.SetAPIKey(os.Getenv("OPENAI_API_KEY")) // load from env and validate before calls Defensive patterns
Strategy: try-catch
Validate before calling
null
Try / catch
if err != nil {
var status, msg string
if n, _ := fmt.Sscanf(err.Error(), "openai %s: %s", &status, &msg); n == 2 {
switch {
case strings.HasPrefix(status, "429"): scheduleRetry()
case strings.HasPrefix(status, "401"): refreshAPIKey()
default: logAPIError(status, msg)
}
}
} Prevention
- Validate API key and model name before sending
- Implement 429 backoff handling
- Keep base URL and key scope (project/org) correct
When it happens
Trigger: Any non-2xx response from the OpenAI API carrying the standard error JSON: invalid API key (401), rate limits (429), invalid model name (404/400), malformed request body (400), quota exceeded (429), server errors with structured bodies.
Common situations: Expired or rotated API keys; exceeding RPM/TPM rate limits; using a model name the account/key cannot access; requests sent to the wrong api_base (e.g. Azure endpoint with OpenAI client); prompt exceeds context window.
Related errors
- sse handler is nil
- ai:model is required
- chatOpts.ClientId is required
- ai:endpoint is required
- anthropic %s: %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/c530b67e772b03bc.
Report an issue: GitHub.