gastownhall/beads · error
failed to fetch work items: %w
Error message
failed to fetch work items: %w
What it means
FetchWorkItems wraps any error from the batched GET /wit/workitems?ids=...&$expand=All call (which itself goes through doRequest) with "failed to fetch work items". It is a transport/execution wrapper: the cause is either a doRequest failure (rate limits, retries exhausted, auth) or an HTTP error returned by the ADO work-items endpoint. It does NOT cover JSON parsing — that produces "failed to parse work items response" instead.
Source
Thrown at internal/ado/client.go:353
}
var all []WorkItem
for start := 0; start < len(ids); start += MaxBatchSize {
end := start + MaxBatchSize
if end > len(ids) {
end = len(ids)
}
chunk := ids[start:end]
parts := make([]string, len(chunk))
for i, id := range chunk {
parts[i] = strconv.Itoa(id)
}
urlStr := addAPIVersion(c.apiBase() + "/wit/workitems?ids=" + strings.Join(parts, ",") + "&$expand=All")
respBody, err := c.doRequest(ctx, http.MethodGet, urlStr, "", nil)
if err != nil {
return nil, fmt.Errorf("failed to fetch work items: %w", err)
}
var envelope listResponse
if err := json.Unmarshal(respBody, &envelope); err != nil {
return nil, fmt.Errorf("failed to parse work items response: %w", err)
}
var items []WorkItem
if err := json.Unmarshal(envelope.Value, &items); err != nil {
return nil, fmt.Errorf("failed to parse work items value: %w", err)
}
all = append(all, items...)
}
return all, nil
}
// buildPullWIQL constructs a safe WIQL query from validated filter fields.View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause (%v of err) for the underlying status/body — APIError carries StatusCode and Body.
- Verify the PAT has 'Work Items (Read)' scope and access to the project/area paths of the returned IDs.
- Split large ID lists into smaller batches (URL length / API limits) and retry.
- Remove or re-resolve stale IDs (deleted work items) before calling; re-run the WIQL query.
- Confirm the client's organization/project URL is correct (wrong org yields 404s from the workitems endpoint).
Example fix
// before
respBody, err := c.doRequest(ctx, http.MethodGet, urlStr, "", nil)
if err != nil { return nil, fmt.Errorf("failed to fetch work items: %w", err) }
// after
caller side:
items, err := c.FetchWorkItems(ctx, ids)
if err != nil {
var apiErr *ado.APIError
if errors.As(err, &apiErr) { log.Printf("ADO %d: %s", apiErr.StatusCode, apiErr.Body) }
return nil, err
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate IDs exist / are readable before batch fetch
for _, id := range ids {
if id <= 0 { return fmt.Errorf("invalid work item id %d", id) }
}
if len(ids) > 200 { ids = ids[:200] } // keep URL within limits Try / catch
items, err := client.FetchWorkItems(ctx, ids)
if err != nil {
var apiErr *ado.APIError
if errors.As(err, &apiErr) {
switch apiErr.StatusCode {
case 401, 403: // fix PAT / permissions
case 400: // trim id list, re-run WIQL
default: // transient: retry
}
}
return err
} Prevention
- Check PAT scope ('Work Items (Read)') and area-path permissions before batch reads.
- Chunk ID lists to a few hundred per request.
- Re-run WIQL queries to prune deleted work-item IDs.
- Use errors.As with *ado.APIError to branch on status code.
- Validate the configured organization/project URL at client startup.
When it happens
Trigger: Calling FetchWorkItems (including via fetchWorkItemsByWIQL, which resolves WIQL results into IDs then calls FetchWorkItems) when the batched ids GET fails: retries exhausted on 429/5xx, invalid/nonexistent work-item IDs, insufficient PAT scope, revoked PAT, or network failure.
Common situations: WIQL query returns IDs the caller's PAT cannot read (area-path permissions); deleted/recycled work-item IDs in the id list; huge id batches exceeding URL limits; org URL misconfigured in the client base URL.
Related errors
- failed to add work item link: %w
- failed to remove work item link: %w
- failed to list projects: %w
- transient error %d (attempt %d/%d)
- max retries (%d) exceeded: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9068c0614261cc5e.
Report an issue: GitHub.