gastownhall/beads · error
failed to parse projects response: %w
Error message
failed to parse projects response: %w
What it means
Within FetchProjects' pagination loop, each page's JSON body is unmarshalled into ProjectsResponse. This error wraps a json.Unmarshal failure for a page. The library throws it when the response shape does not match {projects:{nodes:[...],pageInfo:{...}}} — decode failure, not a transport failure.
Source
Thrown at internal/linear/client.go:1480
"first": MaxPageSize,
}
if cursor != "" {
variables["after"] = cursor
}
req := &GraphQLRequest{
Query: projectsQuery,
Variables: variables,
}
data, err := c.Execute(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to fetch projects: %w", err)
}
var projectsResp ProjectsResponse
if err := json.Unmarshal(data, &projectsResp); err != nil {
return nil, fmt.Errorf("failed to parse projects response: %w", err)
}
allProjects = append(allProjects, projectsResp.Projects.Nodes...)
if !projectsResp.Projects.PageInfo.HasNextPage {
break
}
cursor = projectsResp.Projects.PageInfo.EndCursor
}
return allProjects, nil
}
// CreateProject creates a new project in Linear.
func (c *Client) CreateProject(ctx context.Context, name, description, state string) (*Project, error) {
query := `
mutation CreateProject($input: ProjectCreateInput!) {
projectCreate(input: $input) {View on GitHub (pinned to 71377f2769)
Solutions
- Log/dump the raw `data` for the failing page to see the real shape.
- Check for a GraphQL "errors" key in the payload and surface its message.
- Diff ProjectsResponse/Project/PageInfo structs against the current Linear GraphQL schema and fix drift.
- Retry the request directly against the GraphQL endpoint to rule out gateway/proxy body substitution.
- Upgrade or pin the client library to match the Linear API version in use.
Example fix
// before
var projectsResp ProjectsResponse
if err := json.Unmarshal(data, &projectsResp); err != nil { return nil, err }
// after
var probe struct{ Projects json.RawMessage `json:"projects"`; Errors json.RawMessage `json:"errors"` }
_ = json.Unmarshal(data, &probe)
if probe.Errors != nil { return nil, fmt.Errorf("graphql error: %s", string(probe.Errors)) }
var projectsResp ProjectsResponse
if err := json.Unmarshal(data, &projectsResp); err != nil { return nil, err } Defensive patterns
Strategy: type-guard
Type guard
func isProjectsResponse(data []byte) bool {
var probe struct {
Projects *struct {
Nodes []json.RawMessage `json:"nodes"`
PageInfo json.RawMessage `json:"pageInfo"`
} `json:"projects"`
}
return json.Unmarshal(data, &probe) == nil && probe.Projects != nil
} Try / catch
projects, err := client.FetchProjects(ctx, state)
if err != nil {
var ute *json.UnmarshalTypeError
if errors.As(err, &ute) {
return fmt.Errorf("projects response shape mismatch at field %s — check Linear schema version", ute.Field)
}
return err
} Prevention
- Add a contract test fetching page 1 of projects in CI to detect schema drift.
- Log raw bytes on unmarshal failure to see the true payload.
- Keep the Project struct minimal (only fields consumed) to reduce drift surface.
- Verify gateways don't rewrite 200 responses with error JSON.
When it happens
Trigger: c.Execute returned HTTP-200 data of unexpected shape: a GraphQL errors envelope instead of data, a gateway error page, or Project/ProjectsResponse/PageInfo structs out of sync with the Linear schema (e.g. field renamed or type changed so encoding/json fails).
Common situations: Linear schema change breaking the Project struct; API version mismatch after Linear updates GraphQL; proxy injecting a JSON error object; struct field type mismatch (e.g. progress float vs string).
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 teams response: %w
- failed to parse create project response: %w
- failed to fetch projects: %w
- parsing waits-for metadata to set also_blocks: %w
- re-parsing metadata: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3d17c5eefd559dfc.
Report an issue: GitHub.