Tencent/WeKnora · error
Zhipu API returned status %d (%s): %s
Error message
Zhipu API returned status %d (%s): %s
What it means
When the Zhipu API returns a non-200 status, zhipuHTTPError first tries to decode a structured error object from the body; if present it reports status, error code, and message in one formatted error. This is the structured variant of the non-200 handling path.
Source
Thrown at internal/infrastructure/web_search/zhipu.go:231
}
return time.Time{}, false
}
func readZhipuResponseBody(reader io.Reader) ([]byte, error) {
body, err := io.ReadAll(io.LimitReader(reader, maxZhipuResponseBytes+1))
if err != nil {
return nil, fmt.Errorf("failed to read Zhipu response: %w", err)
}
if len(body) > maxZhipuResponseBytes {
return nil, fmt.Errorf("Zhipu response exceeds %d bytes", maxZhipuResponseBytes)
}
return body, nil
}
func zhipuHTTPError(statusCode int, body []byte) error {
var response zhipuSearchResponse
if err := json.Unmarshal(body, &response); err == nil && (response.Error.Code != "" || response.Error.Message != "") {
return fmt.Errorf("Zhipu API returned status %d (%s): %s", statusCode, response.Error.Code, response.Error.Message)
}
detail := strings.TrimSpace(string(body))
if len(detail) > 4096 {
detail = detail[:4096]
}
if detail == "" {
return fmt.Errorf("Zhipu API returned status %d", statusCode)
}
return fmt.Errorf("Zhipu API returned status %d: %s", statusCode, detail)
}
type zhipuSearchRequest struct {
SearchQuery string `json:"search_query"`
SearchEngine string `json:"search_engine"`
SearchIntent bool `json:"search_intent"`
Count int `json:"count"`
ContentSize string `json:"content_size"`
}View on GitHub (pinned to 988cbb0330)
Solutions
- Read the embedded error code: 401/403 → fix API key; 429 → back off and retry; 4xx → fix request params
- Confirm the Authorization header carries a valid Bearer token (p.apiKey is set)
- Check Zhipu service status if 5xx persists
- Implement retry-with-backoff for 429/5xx only
Example fix
// before
if err != nil { log.Println(err); os.Exit(1) } // opaque
// after
if err != nil {
var apiErr *ZhipuStatusError
if errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusTooManyRequests {
time.Sleep(backoff); return retry(ctx)
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
if !strings.HasPrefix(apiURL, "https://") { return errors.New("zhipu endpoint must be https") }
if apiKey == "" { return errors.New("zhipu api key required") } Type guard
func statusCodeOf(err error) (int, bool) {
m := regexp.MustCompile(`status (\d{3})`).FindStringSubmatch(err.Error())
if m == nil { return 0, false }
c, _ := strconv.Atoi(m[1]); return c, true
} Try / catch
results, err := provider.Search(ctx, q)
if err != nil {
if sc, ok := statusCodeOf(err); ok && (sc == 429 || sc >= 500) { return retryWithBackoff(ctx, q) }
return err
} Prevention
- Retry only 429/5xx; never retry 401/403/400
- Keep the API key fresh and monitor quota usage
- Log the structured code+message from the error for triage
- Set up alerts on repeated non-200s from the provider
When it happens
Trigger: Calling Search() when Zhipu returns 4xx/5xx AND the body contains a parseable {error:{code,message}} object.
Common situations: 401/403 from an invalid or expired API key; 429 rate limiting; 400 from invalid search_engine or query parameters.
Related errors
- Zhipu API error (%s): %s
- unexpected status %d: %s
- get token error: code=%d msg=%s
- Zhipu API returned status %d
- Zhipu API returned status %d: %s
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/b79979dc6f00b417.
Report an issue: GitHub.