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
- 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.
- Log or print the raw body on this error to see what the server actually returned (html vs json).
- Check for SSO/proxy interception: test the same URL with curl using the same credentials.
- 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
- Point Client.URL at the instance root, never a UI or proxy path
- Check Content-Type of responses when debugging
- Watch for SSO/proxy HTML injection on API routes
- Pin APIVersion explicitly rather than relying on defaults
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
- parse search 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/dfef77d0d50d0fbc.
Report an issue: GitHub.