wtfutil/wtf · error
failed to parse JQL search response: %v
Error message
failed to parse JQL search response: %v
What it means
searchWithNewAPI fails with this error when utils.ParseJSON cannot decode the /rest/api/3/search/jql response body into the JQLSearchResult struct. The HTTP call succeeded but the body doesn't match the expected JSON shape (issues array, pagination fields, etc.).
Source
Thrown at modules/jira/client.go:234
jqlURL := fmt.Sprintf("/rest/api/3/search/jql?%s", v.Encode())
resp, err := widget.jiraRequest(jqlURL)
if err != nil {
return nil, err
}
// Parse the JQL response which contains issue IDs
type JQLSearchResult struct {
Issues []struct {
ID string `json:"id"`
} `json:"issues"`
}
jqlResult := &JQLSearchResult{}
err = utils.ParseJSON(jqlResult, bytes.NewReader(resp))
if err != nil {
return nil, fmt.Errorf("failed to parse JQL search response: %v", err)
}
if len(jqlResult.Issues) == 0 {
// Return empty result if no issues found
return &SearchResult{Issues: []Issue{}}, nil
}
// Now get full issue details for each ID
searchResult := &SearchResult{Issues: []Issue{}}
for i, issue := range jqlResult.Issues {
// Limit to prevent too many API calls
if i >= 20 {
break
}
fullIssue, err := widget.getIssueByID(issue.ID)
if err != nil {View on GitHub (pinned to bb838c1ccb)
Solutions
- Log the raw response body to see the actual JSON returned
- Compare the JQLSearchResult struct tags with the current /rest/api/3/search/jql response schema from Atlassian docs
- Bypass/update any proxy that might rewrite the response
- Update the client (or struct tags) to the current API response format
Example fix
// before
issues []struct {
Key string `json:"key"`
}
// after (match current API payload)
issues []struct {
Key string `json:"key"`
Fields struct {
Summary string `json:"summary"`
} `json:"fields"`
} `json:"issues"` Defensive patterns
Strategy: type-guard
Type guard
func looksLikeJQLSearchResponse(body []byte) bool {
var probe struct {
Issues []json.RawMessage `json:"issues"`
}
return json.Unmarshal(body, &probe) == nil
} Try / catch
result, err := widget.IssuesFor(ctx, username, jql)
if err != nil {
if strings.Contains(err.Error(), "failed to parse JQL search response") {
log.Printf("response schema drift or proxy interference: %v", err)
}
return err
} Prevention
- Keep JQLSearchResult json tags aligned with the current Atlassian schema
- Snapshot real API responses in fixtures and parse them in tests
- Ensure proxies/gateways don't inject HTML error pages on 200
- Handle null fields defensively in the struct (pointers/omitempty)
When it happens
Trigger: Jira returns 200 with a body whose JSON keys/types differ from JQLSearchResult (API shape change), or an error payload/HTML page arrives with a 200-like status, or a truncated/garbled body from a proxy.
Common situations: Atlassian changing field names/types in search/jql responses, an API gateway or proxy returning an HTML error page, a stale fork of the client missing new response fields, gzip/encoding issues from intermediaries.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse issue %s: %v
- failed to marshal request: %v
- failed to extract account ID from converted query: %s
- decoding response: %w
- no conversion result for username: %s
AI-assisted analysis of wtfutil/wtf@bb838c1ccb (2026-09-03).
Data as JSON: /api/errors/e1bbe1f163c2ff20.
Report an issue: GitHub.