gastownhall/beads · error

failed to parse projects value: %w

Error message

failed to parse projects value: %w

What it means

This error means the list envelope decoded but the nested 'value' field could not be unmarshalled into []Project. The top-level JSON looked right, but the items inside 'value' do not match the Project struct (unexpected field types or 'value' not an array).

Source

Thrown at internal/ado/client.go:582

}

// 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 listResponse
	if err := json.Unmarshal(respBody, &envelope); err != nil {
		return nil, fmt.Errorf("failed to parse work item types response: %w", err)
	}

	var types []WorkItemType

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect envelope.Value raw JSON and compare against the library's Project struct field types
  2. Pin/check the api-version the library sends (addAPIVersion) against ADO's current projects schema
  3. Upgrade the ado package to a version matching the current ADO response schema
  4. If using a mock/proxy for tests, fix the fixture so 'value' is an array of Project-shaped objects

Example fix

// before (fixture)
{"value": {"id": 1, "name": "p"}}
// after
{"count": 1, "value": [{"id": "abcd-...", "name": "p"}]}
Defensive patterns

Strategy: type-guard

Type guard

// validate a projects payload shape before trusting it
type listEnvelope struct {
  Count int             `json:"count"`
  Value json.RawMessage `json:"value"`
}
func projectsPayloadOK(body []byte) bool {
  var env listEnvelope
  if json.Unmarshal(body, &env) != nil || env.Value == nil {
    return false
  }
  var arr []map[string]any
  return json.Unmarshal(env.Value, &arr) == nil
}

Try / catch

projects, err := client.ListProjects(ctx)
if err != nil {
  if strings.Contains(err.Error(), "failed to parse projects value") {
    return nil, fmt.Errorf("ADO projects schema drift — check api-version/library version: %w", err)
  }
  return nil, err
}

Prevention

When it happens

Trigger: Calling ListProjects when ADO's projects payload has items whose fields don't match the Project struct's types (e.g. an 'id' that isn't a string, or 'value' being an object/null instead of an array) — typically after an API version change or schema drift.

Common situations: ADO rolling out an API response change; using an api-version whose schema differs from what the library expects; mocking proxies (e.g. recorded fixtures) returning differently-typed fields.

Understand the failure class

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/f5445ba42c80c08d. Report an issue: GitHub.