wavetermdev/waveterm · warning
%s
Error message
%s
What it means
sanitizeHostnameInError in pkg/aiusechat/openai/openai-backend.go:42 rewraps a sanitized error string via fmt.Errorf("%s", errStr). It fires when the original error text contained the Wave AI service endpoint hostname, which is replaced with "AI service"/"host" for user display. The error itself is a pass-through of an underlying OpenAI/network error; this wrapper only masks the host. Because it rewraps with %s, the original error chain and sentinel values are lost (errors.Is/As will not match).
Source
Thrown at pkg/aiusechat/openai/openai-backend.go:42
"github.com/wavetermdev/waveterm/pkg/web/sse"
)
// sanitizeHostnameInError removes the Wave cloud hostname from error messages
func sanitizeHostnameInError(err error) error {
if err == nil {
return nil
}
errStr := err.Error()
parsedURL, parseErr := url.Parse(uctypes.DefaultAIEndpoint)
if parseErr == nil && parsedURL.Host != "" {
if strings.Contains(errStr, parsedURL.Host) {
errStr = strings.ReplaceAll(errStr, uctypes.DefaultAIEndpoint, "AI service")
errStr = strings.ReplaceAll(errStr, parsedURL.Host, "host")
}
}
return fmt.Errorf("%s", errStr)
}
// ---------- OpenAI wire types (subset) ----------
type OpenAIChatMessage struct {
MessageId string `json:"messageid"` // internal field for idempotency (cannot send to openai)
Message *OpenAIMessage `json:"message,omitempty"`
FunctionCall *OpenAIFunctionCallInput `json:"functioncall,omitempty"`
FunctionCallOutput *OpenAIFunctionCallOutputInput `json:"functioncalloutput,omitempty"`
Usage *OpenAIUsage
}
type OpenAIMessage struct {
Role string `json:"role"`
Content []OpenAIMessageContent `json:"content"`
}
type OpenAIFunctionCallInput struct {View on GitHub (pinned to a4447c1563)
Solutions
- Read the sanitized message ("AI service"/"host") and diagnose the underlying call (connectivity, auth, request payload) rather than the hostname
- Check network connectivity/proxy settings and API credentials to the AI endpoint
- If you need the raw error (e.g. for errors.Is), capture it before this layer or match on substring, not sentinel errors
- Add logging upstream of sanitizeHostnameInError to keep the unsanitized error internally
Example fix
// before
if errors.Is(err, net.ErrClosed) { ... } // never matches after sanitization
// after
var netErr net.Error
if errors.As(err, &netErr) { ... } // or check err.Error() substrings Defensive patterns
Strategy: fallback
Try / catch
err := RunOpenAIChatStep(ctx, sse, chatOpts, cont)
if err != nil {
// message is host-sanitized; log internally and surface generic guidance
log.Printf("openai step failed: %v", err)
return fmt.Errorf("AI request failed; check connectivity/credentials")
} Prevention
- Monitor connectivity to the AI endpoint separately so sanitized messages still map to actionable alerts
- Capture raw errors in internal logs before sanitization for debugging
- Do not rely on errors.Is/As through this layer; match on message content if needed
- Keep secrets/hostnames out of user-facing paths by keeping sanitization in place
When it happens
Trigger: Any error returned by the OpenAI HTTP step in RunOpenAIChatStep whose message contains the parsed host of uctypes.DefaultAIEndpoint (e.g. connection refused, DNS failure, 4xx/5xx response text referencing the endpoint) is passed through sanitizeHostnameInError and re-emitted as a generic fmt.Errorf string.
Common situations: Network/DNS outages, proxy misconfiguration, expired auth against the Wave AI endpoint, or any API error surfacing the backend URL in its message; developers comparing errors with errors.Is or matching on the raw hostname get no match after sanitization.
Related errors
- wcloud endpoint not set
- wcloud ping endpoint not set
- chat not found: %s
- function call with callId %s not found in chat %s
- API type mismatch: chat has %s, chatOpts has %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/07a96f8db2d9261c.
Report an issue: GitHub.