{"record":{"id":"b2b67ea39eef19ea","repo":"gastownhall/beads","slug":"failed-to-get-work-item-states-w","errorCode":null,"errorMessage":"failed to get work item states: %w","messagePattern":"failed to get work item states: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ado/client.go","lineNumber":612,"sourceCode":"\n\tvar envelope listResponse\n\tif err := json.Unmarshal(respBody, &envelope); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse work item types response: %w\", err)\n\t}\n\n\tvar types []WorkItemType\n\tif err := json.Unmarshal(envelope.Value, &types); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse work item types value: %w\", err)\n\t}\n\treturn types, nil\n}\n\n// GetWorkItemStates returns the states for a given work item type.\nfunc (c *Client) GetWorkItemStates(ctx context.Context, typeName string) ([]WorkItemState, error) {\n\turlStr := addAPIVersion(c.apiBase() + \"/wit/workitemtypes/\" + url.PathEscape(typeName) + \"/states\")\n\trespBody, err := c.doRequest(ctx, http.MethodGet, urlStr, \"\", nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get work item states: %w\", err)\n\t}\n\n\tvar envelope listResponse\n\tif err := json.Unmarshal(respBody, &envelope); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse work item states response: %w\", err)\n\t}\n\n\tvar states []WorkItemState\n\tif err := json.Unmarshal(envelope.Value, &states); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse work item states value: %w\", err)\n\t}\n\treturn states, nil\n}\n","sourceCodeStart":594,"sourceCodeEnd":626,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/ado/client.go#L594-L626","documentation":"This error wraps an HTTP failure from GET {apiBase}/wit/workitemtypes/{typeName}/states in GetWorkItemStates. The request to list states for a specific work item type failed at the transport/status level; the underlying cause is preserved via %w.","triggerScenarios":"Calling Client.GetWorkItemStates(ctx, typeName) when doRequest fails: typeName that doesn't exist (404), typeName needing escaping but corrupt after PathEscape, invalid PAT (401), missing project (404), network error, 429 throttling.","commonSituations":"Passing a display name for a type absent from the project's process template (e.g. 'Epic' in a project using Scrum vs Agile); typo in type name; renamed custom types; PAT scope issues.","solutions":["Verify typeName exists by calling GetWorkItemTypes first (404 usually means the type isn't in this project's process template)","Check the wrapped error's status code to distinguish auth (401) from not-found (404)","Confirm the project configuration in the client matches where the type lives","Use the exact type name as returned by the API (custom templates may rename types)","Retry on 429/5xx with backoff"],"exampleFix":"// before\nstates, err := client.GetWorkItemStates(ctx, \"Epic\") // project uses Scrum: no Epic\n// after\ntypes, _ := client.GetWorkItemTypes(ctx)\nif !containsType(types, \"Epic\") {\n  return nil, fmt.Errorf(\"work item type %q not available in project\", \"Epic\")\n}\nstates, err := client.GetWorkItemStates(ctx, \"Epic\")","handlingStrategy":"validation","validationCode":"// verify the type exists in this project before asking for its states\ntypes, err := client.GetWorkItemTypes(ctx)\nif err != nil {\n  return err\n}\nfound := false\nfor _, t := range types {\n  if t.Name == typeName || t.ReferenceName == typeName {\n    found = true\n    break\n  }\n}\nif !found {\n  return fmt.Errorf(\"work item type %q not present in project's process template\", typeName)\n}","typeGuard":"func hasWorkItemType(types []ado.WorkItemType, name string) bool {\n  for _, t := range types {\n    if t.Name == name {\n      return true\n    }\n  }\n  return false\n}","tryCatchPattern":"states, err := client.GetWorkItemStates(ctx, typeName)\nif err != nil {\n  if strings.Contains(err.Error(), \"404\") {\n    return nil, fmt.Errorf(\"type %q not found in project — check process template: %w\", typeName, err)\n  }\n  return nil, err\n}","preventionTips":["Pass type names exactly as returned by GetWorkItemTypes","Remember custom process templates can rename or omit types (Agile/Scrum/CMMI differ)","Cache the type list per project instead of hardcoding type names","Handle 429 throttling in polling loops"],"tags":["azure-devops","http","work-item-states","validation"],"backgroundTag":"http-request-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}