Tencent/WeKnora · error
failed to unmarshal response: %w
Error message
failed to unmarshal response: %w
What it means
Returned by KeenableProvider.Search when json.Unmarshal cannot decode the API response body into keenableSearchResponse. The body was received and read successfully, but it is not the JSON shape the provider expects — often HTML from an error/login page, truncated JSON, or a schema change at the Keenable API. The json error is wrapped for inspection.
Source
Thrown at internal/infrastructure/web_search/keenable.go:117
if err != nil {
return nil, fmt.Errorf("failed to execute request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBody, _ := io.ReadAll(resp.Body)
logger.Warnf(ctx, "[WebSearch][Keenable] API returned status %d: %s", resp.StatusCode, string(respBody))
return nil, fmt.Errorf("keenable API returned status %d: %s", resp.StatusCode, string(respBody))
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
var respData keenableSearchResponse
if err := json.Unmarshal(respBody, &respData); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
results := make([]*types.WebSearchResult, 0, len(respData.Results))
for _, item := range respData.Results {
if maxResults > 0 && len(results) >= maxResults {
break
}
// Keenable returns both a short "description" and a longer "snippet"
// excerpt. Prefer the short description as the summary snippet and keep
// the longer excerpt as Content (used by RAG compression). Fall back to
// whichever is present so we never drop the only available text.
snippet := item.Description
if snippet == "" {
snippet = item.Snippet
}
result := &types.WebSearchResult{
Title: item.Title,
URL: item.URL,View on GitHub (pinned to 988cbb0330)
Solutions
- Log/print the raw respBody on failure to see whether it is HTML, empty, or truncated JSON.
- If the body is HTML, look for an intercepting proxy, captive portal, or wrong baseURL in the provider config.
- Compare the actual JSON against the keenableSearchResponse struct fields/types; update the struct if the API schema changed.
- Pin or update the provider version to match the current Keenable API contract.
Example fix
// before: opaque unmarshal failure
if err := json.Unmarshal(respBody, &respData); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
// after: include a body snippet for diagnosis
if err := json.Unmarshal(respBody, &respData); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w (body: %.200s)", err, string(respBody))
} Defensive patterns
Strategy: try-catch
Type guard
func isLikelyJSON(b []byte) bool {
t := bytes.TrimSpace(b)
return len(t) > 0 && (t[0] == '{' || t[0] == '[')
}
// call before unmarshalling:
if !isLikelyJSON(respBody) {
return nil, fmt.Errorf("non-JSON response body: %.200s", string(respBody))
} Try / catch
if err := json.Unmarshal(respBody, &respData); err != nil {
log.Printf("keenable unmarshal failed: %v, body=%.500s", err, string(respBody))
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
} Prevention
- Include a raw-body snippet in unmarshal error logs to speed up diagnosis.
- Add a contract/integration test that decodes a recorded live Keenable response.
- Watch provider changelogs for response schema changes and update structs promptly.
- Check for proxies/interceptors in the deployment environment that may replace JSON with HTML.
When it happens
Trigger: Search (internal/infrastructure/web_search/keenable.go:117) read a 200 body but json.Unmarshal(respBody, &respData) fails — non-JSON HTML body, malformed/truncated JSON, or fields whose types no longer match keenableSearchResponse.
Common situations: Proxy/captive portal returning HTML with status 200; Keenable API contract change after a version bump; CDN error interstitial; body cut off mid-stream by a short client timeout.
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 Metaso response: %w
- unmarshal page: %w
- unmarshal database: %w
- unmarshal data_source: %w
- unmarshal block children response: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/870483d4d367eb60.
Report an issue: GitHub.