{"record":{"id":"c062ccb0f94229d4","repo":"Tencent/WeKnora","slug":"zhipu-api-returned-status-d-s","errorCode":null,"errorMessage":"Zhipu API returned status %d: %s","messagePattern":"Zhipu API returned status (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/zhipu.go","lineNumber":240,"sourceCode":"\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}\n\ntype zhipuSearchResult struct {","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/zhipu.go#L222-L258","documentation":"Fallback case of zhipuHTTPError: non-200 status, no parseable error object, but a non-empty body. The provider includes up to 4096 bytes of the trimmed raw body as detail so developers can see the actual failure payload.","triggerScenarios":"Calling Search() when Zhipu returns 4xx/5xx with an unstructured body (plain text, HTML error page, non-standard JSON shape).","commonSituations":"WAF/CDN blocking the client and returning an HTML block page; a gateway returning plain-text errors; API version change moving the error fields.","solutions":["Inspect the appended body detail to identify the actual blocker (HTML page = proxy/WAF, JSON = schema drift)","Whitelist your egress IPs if a WAF block page appears","Update request/response handling to match the current Zhipu API error schema","Retry only if the detail indicates a transient 5xx condition"],"exampleFix":"// before\nfmt.Println(err) // Zhipu API returned status 403: <html>blocked...</html>\n// after\nif strings.Contains(err.Error(), \"<html\") { log.Warn(\"proxy/WAF interference suspected\") }","handlingStrategy":"try-catch","validationCode":"if apiURL == \"\" || apiKey == \"\" { return errors.New(\"zhipu endpoint and key must be configured\") }","typeGuard":"func hasBodyDetail(err error) (detail string, ok bool) {\n    i := strings.Index(err.Error(), \"): \"); return \"\", i >= 0\n}","tryCatchPattern":"results, err := provider.Search(ctx, q)\nif err != nil {\n    if strings.Contains(err.Error(), \"<html\") { log.Warn(\"WAF/proxy page detected in zhipu error body\") }\n    return err\n}","preventionTips":["Read the appended body detail before deciding how to handle","Watch for HTML in error bodies — sign of WAF/CDN blocking","Whitelist egress IPs with the provider if blocks recur","Track API schema changes that move error fields"],"tags":["http-status","error-detail","zhipu","web-search"],"backgroundTag":"http-4xx-error","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}