{"record":{"id":"96a0009069972c94","repo":"gastownhall/beads","slug":"failed-to-parse-teams-response-w","errorCode":null,"errorMessage":"failed to parse teams response: %w","messagePattern":"failed to parse teams response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/client.go","lineNumber":1433,"sourceCode":"\t\t\t\t\tname\n\t\t\t\t\tkey\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t`\n\n\treq := &GraphQLRequest{\n\t\tQuery: query,\n\t}\n\n\tdata, err := c.Execute(ctx, req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch teams: %w\", err)\n\t}\n\n\tvar teamsResp TeamsResponse\n\tif err := json.Unmarshal(data, &teamsResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse teams response: %w\", err)\n\t}\n\n\treturn teamsResp.Teams.Nodes, nil\n}\n\n// FetchProjects retrieves projects from Linear with optional filtering by state.\n// state can be: \"planned\", \"started\", \"paused\", \"completed\", \"canceled\", or \"all\"/\"\".\nfunc (c *Client) FetchProjects(ctx context.Context, state string) ([]Project, error) {\n\tvar allProjects []Project\n\tvar cursor string\n\n\tfilter := map[string]interface{}{\n\t\t\"team\": map[string]interface{}{\n\t\t\t\"id\": map[string]interface{}{\n\t\t\t\t\"eq\": c.TeamID,\n\t\t\t},\n\t\t},\n\t}","sourceCodeStart":1415,"sourceCodeEnd":1451,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/client.go#L1415-L1451","documentation":"After fetching teams successfully at the transport level, FetchTeams unmarshals the JSON into TeamsResponse ({teams:{nodes:[...]}}). This error wraps json.Unmarshal failure — the body's shape didn't match the struct. The library throws it to separate decode problems from request problems.","triggerScenarios":"c.Execute succeeded but the payload isn't the expected shape: response is a GraphQL errors envelope with HTTP 200, a proxy returned an HTML page, or TeamsResponse/Team structs no longer match the Linear schema (field renamed, type changed, nullability mismatch causing decode error).","commonSituations":"Linear API schema evolution breaking generated structs; corporate TLS-inspecting proxy substituting an error page; an API gateway returning JSON error objects; version mismatch between client library and Linear API version.","solutions":["Dump the raw `data` payload to inspect the actual JSON structure.","Check whether the body contains a GraphQL \"errors\" array and surface that instead of unmarshalling into TeamsResponse.","Diff the Team/TeamsResponse structs against the current Linear GraphQL schema and update field names/types.","Bypass any proxy/gateway to confirm the body is genuine GraphQL JSON.","Update the library/client to a version matching the current Linear API schema."],"exampleFix":"// before\nvar teamsResp TeamsResponse\nif err := json.Unmarshal(data, &teamsResp); err != nil { return nil, err }\n// after\nvar probe map[string]json.RawMessage\nif err := json.Unmarshal(data, &probe); err != nil { return nil, err }\nif _, ok := probe[\"teams\"]; !ok {\n    return nil, fmt.Errorf(\"unexpected teams payload: %s\", truncate(string(data), 200))\n}\nvar teamsResp TeamsResponse\nif err := json.Unmarshal(data, &teamsResp); err != nil { return nil, err }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isTeamsResponse(data []byte) bool {\n    var probe struct {\n        Teams *struct{ Nodes []json.RawMessage `json:\"nodes\"` } `json:\"teams\"`\n    }\n    return json.Unmarshal(data, &probe) == nil && probe.Teams != nil\n}","tryCatchPattern":"teams, err := client.FetchTeams(ctx)\nif err != nil {\n    var ute *json.UnmarshalTypeError\n    if errors.As(err, &ute) {\n        return fmt.Errorf(\"linear schema drift in teams response (field %s): %w\", ute.Field, err)\n    }\n    return err\n}","preventionTips":["Diff Team/TeamsResponse structs against the live Linear schema after API version bumps.","Keep a CI integration test calling FetchTeams to catch decode breaks immediately.","Inspect raw payloads (json.Indent into logs) when a decode error first appears.","Rule out proxy response substitution by hitting the GraphQL endpoint directly."],"tags":["go","json","unmarshal","linear-api"],"backgroundTag":"response-unmarshal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}