{"record":{"id":"a56684693bb68970","repo":"wavetermdev/waveterm","slug":"s","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"pkg/aiusechat/anthropic/anthropic-backend.go","lineNumber":357,"sourceCode":"\tcase map[string]interface{}:\n\t\treturn json.RawMessage(raw), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"tool input is not an object\")\n\t}\n}\n\n// sanitizeHostnameInError removes the Wave cloud hostname from error messages\nfunc sanitizeHostnameInError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\terrStr := err.Error()\n\tparsedURL, parseErr := url.Parse(uctypes.DefaultAIEndpoint)\n\tif parseErr == nil && parsedURL.Host != \"\" && strings.Contains(errStr, parsedURL.Host) {\n\t\terrStr = strings.ReplaceAll(errStr, uctypes.DefaultAIEndpoint, \"AI service\")\n\t\terrStr = strings.ReplaceAll(errStr, parsedURL.Host, \"host\")\n\t}\n\treturn fmt.Errorf(\"%s\", errStr)\n}\n\n// makeThinkingOpts creates thinking options based on level and max tokens\nfunc makeThinkingOpts(thinkingLevel string, maxTokens int) *anthropicThinkingOpts {\n\tif thinkingLevel != uctypes.ThinkingLevelMedium && thinkingLevel != uctypes.ThinkingLevelHigh {\n\t\treturn nil\n\t}\n\n\tmaxThinkingBudget := int(float64(maxTokens) * 0.75)\n\n\t// If 75% of maxTokens is less than minimum, disable thinking\n\tif maxThinkingBudget < AnthropicMinThinkingBudget {\n\t\treturn nil\n\t}\n\n\t// Use the smaller of our default budget or 75% of maxTokens\n\tthinkingBudget := AnthropicThinkingBudget\n\tif thinkingBudget > maxThinkingBudget {","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/anthropic/anthropic-backend.go#L339-L375","documentation":"sanitizeHostnameInError rewrites internal/cloud hostnames (the DefaultAIEndpoint) out of error messages before surfacing them, replacing them with \"AI service\"/\"host\". The final error is rebuilt with fmt.Errorf(\"%s\", errStr). This error is the generic sanitized error text — the message content comes from the underlying transport/API error, with the hostname stripped.","triggerScenarios":"Any upstream error from the Anthropic request path (connection failures, TLS errors, HTTP errors) whose message contains the default AI endpoint host is passed through sanitizeHostnameInError; the returned error is the sanitized string. There is no failure condition here itself — it's the re-wrapping of any error text.","commonSituations":"DNS/connection errors to the AI endpoint shown to users without leaking internal hostnames; proxy misconfigurations surfacing the endpoint URL; users debugging why errors say \"host\" instead of a real hostname.","solutions":["Read the sanitized message to identify the underlying error class (connection refused, TLS, timeout, HTTP status).","To see the real endpoint during debugging, temporarily log the pre-sanitization error server-side.","Fix the root cause indicated by the sanitized text (network, auth, proxy).","If the sanitization makes errors too opaque for your users, include a correlation/request ID in the unsanitized server-side log."],"exampleFix":"// pattern\nerr := runAnthropic(ctx)\nif err != nil {\n    log.Printf(\"[server-only] anthropic failure at %s\", err) // unsanitized source\n    return sanitizeHostnameInError(err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := doRequest(ctx)\nif err != nil {\n    // sanitized text: match on error classes, not hostnames\n    switch {\n    case strings.Contains(err.Error(), \"connection refused\"), strings.Contains(err.Error(), \"no such host\"):\n        return retryWithBackoff(ctx)\n    case strings.Contains(err.Error(), \"status\"):\n        return handleHTTPFailure(err)\n    }\n    return err\n}","preventionTips":["Log the unsanitized error server-side with a correlation ID before sanitizing","Match user-facing handling on error classes, not endpoint hostnames","Remember the endpoint host will appear as \"host\"/\"AI service\" in surfaced errors"],"tags":["error-sanitization","hostname-redaction","anthropic"],"backgroundTag":"hostname-redaction","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}