{"record":{"id":"bd281a3971e66b2a","repo":"Tencent/WeKnora","slug":"zhipu-api-returned-status-d","errorCode":null,"errorMessage":"Zhipu API returned status %d","messagePattern":"Zhipu API returned status (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/zhipu.go","lineNumber":238,"sourceCode":"\t\treturn nil, fmt.Errorf(\"failed to read Zhipu response: %w\", err)\n\t}\n\tif len(body) > maxZhipuResponseBytes {\n\t\treturn nil, fmt.Errorf(\"Zhipu response exceeds %d bytes\", maxZhipuResponseBytes)\n\t}\n\treturn body, nil\n}\n\nfunc zhipuHTTPError(statusCode int, body []byte) error {\n\tvar response zhipuSearchResponse\n\tif err := json.Unmarshal(body, &response); err == nil && (response.Error.Code != \"\" || response.Error.Message != \"\") {\n\t\treturn fmt.Errorf(\"Zhipu API returned status %d (%s): %s\", statusCode, response.Error.Code, response.Error.Message)\n\t}\n\tdetail := strings.TrimSpace(string(body))\n\tif len(detail) > 4096 {\n\t\tdetail = detail[:4096]\n\t}\n\tif detail == \"\" {\n\t\treturn fmt.Errorf(\"Zhipu API returned status %d\", statusCode)\n\t}\n\treturn fmt.Errorf(\"Zhipu API returned status %d: %s\", statusCode, detail)\n}\n\ntype zhipuSearchRequest struct {\n\tSearchQuery  string `json:\"search_query\"`\n\tSearchEngine string `json:\"search_engine\"`\n\tSearchIntent bool   `json:\"search_intent\"`\n\tCount        int    `json:\"count\"`\n\tContentSize  string `json:\"content_size\"`\n}\n\ntype zhipuSearchResponse struct {\n\tID           string              `json:\"id\"`\n\tRequestID    string              `json:\"request_id\"`\n\tSearchResult []zhipuSearchResult `json:\"search_result\"`\n\tError        zhipuError          `json:\"error\"`\n}","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/zhipu.go#L220-L256","documentation":"Fallback case of zhipuHTTPError: the API returned a non-200 status, the body had no parseable error object, and the trimmed body is empty. The caller only learns the numeric status code with no detail.","triggerScenarios":"Calling Search() when Zhipu returns 4xx/5xx with an empty body (e.g. 502/503 from a load balancer, 401 with no body).","commonSituations":"Upstream gateway returning bare 502/503/504 during outages; auth middleware rejecting with an empty body.","solutions":["Log/check the status code: retry 5xx with backoff, fix auth on 401/403","Check Zhipu service status or upstream LB health for 5xx","Add request ID/trace headers if available to correlate with server logs","Treat repeated 5xx as provider outage and fall back to another search provider"],"exampleFix":"// before\nif err != nil { return err }\n// after\nif err != nil {\n    if strings.Contains(err.Error(), \"503\") { return ErrProviderUnavailable } // enables fallback\n    return err\n}","handlingStrategy":"fallback","validationCode":"if apiURL == \"\" { return errors.New(\"zhipu endpoint not configured\") }","typeGuard":"func isEmptyStatusError(err error) bool { re := regexp.MustCompile(`status \\d+$`); return re.MatchString(err.Error()) }","tryCatchPattern":"results, err := provider.Search(ctx, q)\nif err != nil {\n    if isEmptyStatusError(err) { return fallbackProvider.Search(ctx, q) } // bare 5xx likely outage\n    return err\n}","preventionTips":["Configure a secondary search provider for outages","Retry bare 5xx with backoff before failing over","Monitor provider health endpoints","Correlate occurrences with upstream status pages"],"tags":["http-status","empty-response","zhipu","web-search"],"backgroundTag":"http-5xx-server-error","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}