gastownhall/beads · error
parse search response: %w
Error message
parse search response: %w
What it means
SearchIssues wraps errors from json.Unmarshal of a search page's body. The HTTP call succeeded but the payload is not valid JSON or does not match SearchResult's shape (issues, total, nextPageToken, isLast). The library throws it because pagination logic cannot proceed with an uninterpretable page.
Source
Thrown at internal/jira/client.go:211
} else if nextPageToken != "" {
params.Set("nextPageToken", nextPageToken)
}
// v3 uses /search/jql; v2 uses /search (both accept jql as a query param)
searchPath := "search/jql"
if useV2Pagination {
searchPath = "search"
}
apiURL := fmt.Sprintf("%s/%s?%s", c.apiBase(), searchPath, params.Encode())
body, err := c.doRequest(ctx, "GET", apiURL, nil)
if err != nil {
return nil, fmt.Errorf("search issues: %w", err)
}
var result SearchResult
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("parse search response: %w", err)
}
allIssues = append(allIssues, result.Issues...)
if len(result.Issues) == 0 {
break
}
if useV2Pagination {
if startAt+len(result.Issues) >= result.Total {
break
}
startAt += len(result.Issues)
continue
}
if result.IsLast || result.NextPageToken == "" {
break
}
nextPageToken = result.NextPageTokenView on GitHub (pinned to 71377f2769)
Solutions
- Dump the raw body on failure to see whether it's HTML, an error envelope, or malformed JSON.
- Verify APIVersion matches the deployment (v2 vs v3 search endpoints return compatible but distinct payloads).
- Test the identical URL with curl and valid credentials to rule out proxy/SSO rewriting.
- Update the client if your Jira version changed its search response schema.
Example fix
// before
var result SearchResult
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("parse search response: %w", err)
}
// after: include body context
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("parse search response: %w (body: %.200s)", err, string(body))
} Defensive patterns
Strategy: type-guard
Validate before calling
// Detect non-JSON responses at the transport level before parse failures propagate:
func looksLikeHTML(b []byte) bool {
s := bytes.TrimLeft(b, " \t\r\n")
return bytes.HasPrefix(s, []byte("<"))
} Type guard
func isJSONBody(b []byte) bool {
s := bytes.TrimLeft(b, " \t\r\n")
return len(s) > 0 && (s[0] == '{' || s[0] == '[')
} Try / catch
issues, err := client.SearchIssues(ctx, jql)
if err != nil && strings.Contains(err.Error(), "parse search response") {
// body was HTML or wrong schema: dump body, check proxy/SSO, verify APIVersion
log.Printf("search returned non-JSON body; check gateway config")
return
} Prevention
- Exclude API routes from SSO/proxy HTML interstitials
- Verify search payload shape after Jira version upgrades
- Confirm the search endpoint exists for your APIVersion (v2 /search vs v3 /search/jql)
- Log raw bodies when parse errors recur
When it happens
Trigger: A search page response that is HTML (proxy/SSO interstitial), an error object returned with 2xx, or a body whose types clash with SearchResult fields (e.g. issues as object instead of array).
Common situations: API-version mismatch returning a differently-shaped search payload; gateway/auth middleware returning HTML with 200; custom Jira apps altering search responses; truncated bodies on flaky networks.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- parse Jira response: %w
- parse issue response: %w
- parse create response: %w
- marshal create request: %w
- ExternalDoltConfig: must set Socket or (Host, Port)
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/e8302da71afba6ea.
Report an issue: GitHub.