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

  1. Read the API error text after 'openai <status>:' and act on it (401 -> fix key, 429 -> backoff, 404 -> fix model name)
  2. Verify the API key is valid and has quota for the requested model
  3. Implement exponential backoff on 429 responses
  4. 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

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


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