gastownhall/beads · error

parse Jira response: %w

Error message

parse Jira response: %w

What it means

FetchIssueTimestamp wraps errors from json.Unmarshal of the GET /issue/{key}?fields=updated response body. It means the HTTP request succeeded but the body was not valid JSON or did not match the expected {"fields":{"updated":"..."}} shape. The library throws it because a truncated, HTML, or malformed response cannot be interpreted as a Jira issue payload.

Source

Thrown at internal/jira/client.go:151

// FetchIssueTimestamp fetches the updated timestamp for a single Jira issue.
func (c *Client) FetchIssueTimestamp(ctx context.Context, jiraKey string) (time.Time, error) {
	var zero time.Time

	apiURL := fmt.Sprintf("%s/issue/%s?fields=updated", c.apiBase(), url.PathEscape(jiraKey))

	body, err := c.doRequest(ctx, "GET", apiURL, nil)
	if err != nil {
		return zero, fmt.Errorf("fetch issue %s: %w", jiraKey, err)
	}

	var result struct {
		Fields struct {
			Updated string `json:"updated"`
		} `json:"fields"`
	}

	if err := json.Unmarshal(body, &result); err != nil {
		return zero, fmt.Errorf("parse Jira response: %w", err)
	}

	updated, err := ParseTimestamp(result.Fields.Updated)
	if err != nil {
		return zero, fmt.Errorf("parse Jira timestamp: %w", err)
	}

	return updated, nil
}

// searchFields is the default set of fields to request in search/get queries.
const searchFields = "summary,description,status,priority,issuetype,project,assignee,labels,created,updated,resolution"

// SearchIssues queries Jira using JQL and returns all matching issues, handling pagination.
func (c *Client) SearchIssues(ctx context.Context, jql string) ([]Issue, error) {
	var allIssues []Issue
	startAt := 0
	nextPageToken := ""

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify the Client.URL points to the Jira instance root (e.g. https://yourorg.atlassian.net) so the API base resolves to /rest/api/3.
  2. Log or print the raw body on this error to see what the server actually returned (html vs json).
  3. Check for SSO/proxy interception: test the same URL with curl using the same credentials.
  4. Confirm APIVersion (2 vs 3) matches your deployment; wrong-version endpoints may return unexpected payloads.

Example fix

// before: err swallowed, opaque failure
if err := json.Unmarshal(body, &result); err != nil {
    return zero, fmt.Errorf("parse Jira response: %w", err)
}
// after: capture body snippet for diagnosis
if err := json.Unmarshal(body, &result); err != nil {
    return zero, fmt.Errorf("parse Jira response: %w (body: %.200s)", err, string(body))
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go has no pre-call validation for server response bodies; verify reachability/shape first:
resp, err := http.Get(client.URL + "/rest/api/3/myself")
if err != nil || !strings.Contains(resp.Header.Get("Content-Type"), "application/json") {
    // base URL or proxy misconfigured
}

Type guard

func isJSONContentType(h http.Header) bool {
    return strings.Contains(h.Get("Content-Type"), "application/json")
}

Try / catch

ts, err := client.FetchIssueTimestamp(ctx, key)
if err != nil {
    var parseErr *json.UnmarshalTypeError
    if errors.As(err, &parseErr) || strings.Contains(err.Error(), "parse Jira response") {
        // non-JSON body: log, skip this key, alert on proxy/auth config
        return
    }
    return err
}

Prevention

When it happens

Trigger: Calling FetchIssueTimestamp when the Jira server returns a non-JSON body (e.g., an HTML login/SSO page, a proxy error page, or a truncated response) despite a 2xx status.

Common situations: Corporate proxies or SSO interceptors returning HTML with 200 OK; misconfigured base URL pointing at a non-REST endpoint; custom Jira plugins or gateways altering response bodies; network truncation mid-body.

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/dfef77d0d50d0fbc. Report an issue: GitHub.