gastownhall/beads · error
failed to parse projects response: %w
Error message
failed to parse projects response: %w
What it means
This error means ListProjects successfully got an HTTP response, but the body could not be decoded into the library's generic list envelope (json.Unmarshal on the raw body failed). This usually indicates the response is not the expected {"value": [...], "count": n} JSON — e.g. an HTML error page, HTML login redirect, or truncated body.
Source
Thrown at internal/ado/client.go:577
_, err := c.doRequest(ctx, http.MethodPatch, urlStr, "application/json-patch+json", ops)
if err != nil {
return fmt.Errorf("failed to remove work item link: %w", err)
}
return nil
}
// ListProjects returns all team projects in the organization.
// This is an org-level endpoint, not project-scoped.
func (c *Client) ListProjects(ctx context.Context) ([]Project, error) {
urlStr := addAPIVersion(c.orgBase() + "/projects")
respBody, err := c.doRequest(ctx, http.MethodGet, urlStr, "", nil)
if err != nil {
return nil, fmt.Errorf("failed to list projects: %w", err)
}
var envelope listResponse
if err := json.Unmarshal(respBody, &envelope); err != nil {
return nil, fmt.Errorf("failed to parse projects response: %w", err)
}
var projects []Project
if err := json.Unmarshal(envelope.Value, &projects); err != nil {
return nil, fmt.Errorf("failed to parse projects value: %w", err)
}
return projects, nil
}
// GetWorkItemTypes returns the work item types available in the project.
func (c *Client) GetWorkItemTypes(ctx context.Context) ([]WorkItemType, error) {
urlStr := addAPIVersion(c.apiBase() + "/wit/workitemtypes")
respBody, err := c.doRequest(ctx, http.MethodGet, urlStr, "", nil)
if err != nil {
return nil, fmt.Errorf("failed to get work item types: %w", err)
}
var envelope listResponseView on GitHub (pinned to 71377f2769)
Solutions
- Log the raw response body to see what was actually returned (HTML page? empty? partial JSON?)
- Verify you are not behind an auth proxy that intercepts the request and returns HTML
- Confirm the org URL is the ADO API endpoint, not the web UI host
- Retry — truncated bodies from transient network issues decode badly
- Update the library if ADO changed its API response shape for projects
Defensive patterns
Strategy: try-catch
Try / catch
projects, err := client.ListProjects(ctx)
if err != nil {
if strings.Contains(err.Error(), "failed to parse projects response") {
// non-JSON body: log it for diagnosis, likely proxy/auth HTML
return nil, fmt.Errorf("non-JSON response from ADO (proxy or auth page?): %w", err)
}
return nil, err
} Prevention
- Ensure no auth proxy intercepts dev.azure.com traffic
- Run a manual curl of the projects endpoint to confirm JSON responses
- Watch ADO status for service degradations
- Keep the library updated for ADO response-shape changes
When it happens
Trigger: Calling ListProjects when the server returns 200/other with a non-JSON body: proxy/login HTML pages, HTML error pages behind a misconfigured URL, empty body, or BOM/encoding issues in the response.
Common situations: Corporate proxies returning an HTML auth page with 200; hitting the wrong URL that serves HTML; ADO outage returning an error page; TLS-terminating proxy mangling the response.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse work item types response: %w
- failed to parse work item states response: %w
- failed to parse projects value: %w
- failed to parse work item types value: %w
- parsing JSON: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7c3beb62c981ae0c.
Report an issue: GitHub.