Tencent/WeKnora · error
failed to unmarshal Zhipu response: %w
Error message
failed to unmarshal Zhipu response: %w
What it means
The Zhipu provider received an HTTP 200 response whose body is not valid JSON matching the zhipuSearchResponse schema. json.Unmarshal failed, so the provider wraps the decode error. This indicates the API returned something other than the expected search-result payload.
Source
Thrown at internal/infrastructure/web_search/zhipu.go:159
logger.Infof(ctx, "[WebSearch][Zhipu] query=%q maxResults=%d engine=%s", preparedQuery, maxResults, p.searchEngine)
resp, err := p.client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to execute Zhipu request: %w", err)
}
defer resp.Body.Close()
respBody, err := readZhipuResponseBody(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, zhipuHTTPError(resp.StatusCode, respBody)
}
var response zhipuSearchResponse
if err := json.Unmarshal(respBody, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal Zhipu response: %w", err)
}
if response.Error.Message != "" || response.Error.Code != "" {
return nil, fmt.Errorf("Zhipu API error (%s): %s", response.Error.Code, response.Error.Message)
}
results := make([]*types.WebSearchResult, 0, len(response.SearchResult))
for _, item := range response.SearchResult {
if strings.TrimSpace(item.Title) == "" && strings.TrimSpace(item.Link) == "" {
continue
}
result := &types.WebSearchResult{
Title: item.Title,
URL: item.Link,
Snippet: item.Content,
Source: "zhipu",
}
if includeDate {
if publishedAt, ok := parseZhipuDate(item.PublishDate); ok {View on GitHub (pinned to 988cbb0330)
Solutions
- Log the raw response body on this failure to see what was actually returned
- Verify you are targeting a current, supported Zhipu API endpoint/version
- Check for proxies or gateways rewriting the response body
- Add a content-type check before unmarshalling
Example fix
// before
respBody, err := readZhipuResponseBody(resp.Body)
// after
respBody, err := readZhipuResponseBody(resp.Body)
if err == nil && !json.Valid(respBody) {
return nil, fmt.Errorf("non-JSON response: %.200s", respBody)
} Defensive patterns
Strategy: try-catch
Validate before calling
if resp.StatusCode == 200 && !strings.Contains(resp.Header.Get("Content-Type"), "json") { return errors.New("unexpected content-type from zhipu") } Type guard
func isUnmarshalError(err error) bool { var ue *json.UnmarshalTypeError; return errors.As(err, &ue) } Try / catch
results, err := provider.Search(ctx, q)
if err != nil && strings.Contains(err.Error(), "failed to unmarshal Zhipu response") {
log.WithError(err).Warn("zhipu returned non-JSON body; check proxy/API version")
} Prevention
- Pin/verify the Zhipu API endpoint version you target
- Log raw bodies on decode failures to diagnose schema drift
- Check Content-Type before decoding
- Alert on spikes of unmarshal failures (usually infra, not code)
When it happens
Trigger: Calling Search() when Zhipu returns a 200 with an HTML error page, truncated body, or an unexpected JSON shape (schema change on the API side).
Common situations: A gateway/proxy intercepting the response and returning HTML; API version drift changing the response schema; a captive-portal or WAF returning a 200 with non-JSON content.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- failed to unmarshal Exa response: %w
- failed to unmarshal response: %w
- failed to unmarshal Metaso response: %w
- failed to marshal Zhipu request: %w
- args must be a string or an array of strings: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/993de3e98610af5e.
Report an issue: GitHub.