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

  1. Log the raw response body to see the actual JSON returned
  2. Compare the JQLSearchResult struct tags with the current /rest/api/3/search/jql response schema from Atlassian docs
  3. Bypass/update any proxy that might rewrite the response
  4. 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

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.

Related errors


AI-assisted analysis of wtfutil/wtf@bb838c1ccb (2026-09-03). Data as JSON: /api/errors/e1bbe1f163c2ff20. Report an issue: GitHub.