gastownhall/beads · error
fetch issue %s: %w
Error message
fetch issue %s: %w
What it means
FetchIssueTimestamp performs a GET to {apiBase}/issue/{key}?fields=updated and wraps any transport/HTTP error from doRequest as 'fetch issue %s: %w' with the Jira issue key. The wrapped cause carries the real reason (network failure, 401/403, 404, rate limit).
Source
Thrown at internal/jira/client.go:141
// apiBase returns the versioned REST API base URL, e.g. "https://host/rest/api/3".
func (c *Client) apiBase() string {
v := c.APIVersion
if v == "" {
v = "3"
}
return c.URL + "/rest/api/" + v
}
// 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, nilView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause: fix auth (token/credentials) if 401/403, or the URL/base if 404
- Verify network connectivity and VPN access to the Jira host
- Confirm the issue key is correct and the issue still exists in Jira
- Retry on transient failures (429/5xx), honoring Jira rate-limit headers
Example fix
// before
t, err := client.FetchIssueTimestamp(ctx, "WRONG-999")
// after
// verify key exists, then handle/retry
t, err := client.FetchIssueTimestamp(ctx, "PROJ-123")
if err != nil {
var retriable = errors.Is(err, context.DeadlineExceeded) // inspect cause
_ = retriable
} Defensive patterns
Strategy: retry
Validate before calling
// verify reachability before calling
resp, err := http.Get(jiraBase + "/rest/api/2/myself")
if err != nil || resp.StatusCode >= 400 { /* fix auth/url first */ } Try / catch
t, err := client.FetchIssueTimestamp(ctx, key)
if err != nil {
var we interface{ Temporary() bool }
if errors.As(err, &we) && we.Temporary() {
// retry with backoff
}
// else: auth/404 — do not retry, fix credentials or key
} Prevention
- Validate Jira credentials and base URL in a startup smoke check
- Handle 429 with backoff honoring Retry-After
- Confirm issue keys before lookup; escape keys properly
When it happens
Trigger: Calling FetchIssueTimestamp when the Jira instance is unreachable, credentials are invalid, the issue key does not exist (or PathEscape-mangled key is malformed), or the API base URL is wrong.
Common situations: Expired or rotated Jira API tokens; VPN/network outage; wrong jiraBase configured so apiBase points to a non-existent REST path; issue deleted or key typo'd; Jira rate limiting (429).
Related errors
- search issues: %w
- get issue %s: %w
- failed to read response (attempt %d/%d): %w
- failed to list projects: %w
- pypi api returned status %d
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/cf35d377442fbd28.
Report an issue: GitHub.