gastownhall/beads · error
failed to fetch issues since %s: %w
Error message
failed to fetch issues since %s: %w
What it means
FetchIssuesSince failed on the HTTP request while fetching issues updated after the given timestamp. The library wraps the transport/request error from doRequest, including the RFC3339 since value for context.
Source
Thrown at internal/gitlab/client.go:314
case <-ctx.Done():
return allIssues, ctx.Err()
default:
}
params := map[string]string{
"per_page": strconv.Itoa(MaxPageSize),
"page": strconv.Itoa(page),
"updated_after": sinceStr,
}
if state != "" && state != "all" {
params["state"] = state
}
applyFilter(params, filter)
urlStr := c.buildURL(c.issuesBasePath(), params)
respBody, headers, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)
if err != nil {
return nil, fmt.Errorf("failed to fetch issues since %s: %w", sinceStr, err)
}
var issues []Issue
if err := json.Unmarshal(respBody, &issues); err != nil {
return nil, fmt.Errorf("failed to parse issues response: %w", err)
}
allIssues = append(allIssues, issues...)
// Check for next page
nextPage := headers.Get("X-Next-Page")
if nextPage == "" {
break
}
page++
// Guard against infinite pagination loops from malformed responses
if page > MaxPages {View on GitHub (pinned to 71377f2769)
Solutions
- Retry the sync after checking network/connectivity; honor Retry-After on 429
- Refresh the GitLab token and re-check scopes (read_api)
- Verify the since timestamp is valid UTC (RFC3339) and not in the future
- Inspect the wrapped %w error for status code and take corresponding action
Example fix
// before
issues, err := client.FetchIssuesSince(ctx, "all", lastSync)
// after
issues, err := client.FetchIssuesSince(ctx, "all", time.Now().UTC().Add(-time.Hour))
if err != nil {
if errors.Is(err, context.DeadlineExceeded) { /* retry with backoff */ }
log.Printf("incremental sync failed: %v", err)
} Defensive patterns
Strategy: retry
Validate before calling
if since.IsZero() || since.After(time.Now().UTC()) {
return errors.New("since timestamp must be a valid past UTC time")
}
if token == "" { return errors.New("gitlab token is empty") } Type guard
func isFetchSinceNetworkErr(err error) bool {
var ne net.Error
return errors.As(err, &ne) || errors.Is(err, context.DeadlineExceeded)
} Try / catch
var issues []gitlab.Issue
err := retry.Do(3, 2*time.Second, func() error {
var e error
issues, e = client.FetchIssuesSince(ctx, "all", lastSync)
return e // retry transient network errors; stop on 401/403
}) Prevention
- Refresh tokens before expiry and store lastSync in UTC RFC3339
- Add timeouts and retries with backoff around sync calls
- Monitor GitLab status/rate limits during sync windows
- Keep the sync interval short so each run fetches few pages
When it happens
Trigger: GET /projects/:id/issues?updated_after=<ts> fails due to network error, 401/403 auth failure, invalid updated_after format, 5xx from GitLab, or context cancellation mid-request.
Common situations: Expired or revoked personal access token, server downtime during incremental sync, offline development, clock-skewed since values, or rate limiting (429) from heavy sync loops.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- pull: %w
- push: %w
- request failed (attempt %d/%d): %w
- failed to read response (attempt %d/%d): %w
- max retries (%d) exceeded: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a484ba68dee6f50a.
Report an issue: GitHub.