gastownhall/beads · error
GraphQL errors: %s
Error message
GraphQL errors: %s
What it means
Linear returned a well-formed GraphQL envelope whose errors array is non-empty (internal/linear/client.go:430): the transport and JSON layers succeeded but GraphQL itself rejected the query or mutation. The client joins all error messages with ';' and returns 'GraphQL errors: ...' with the last HTTP status. Not retried.
Source
Thrown at internal/linear/client.go:430
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, lastStatus, fmt.Errorf("API error: %s (status %d)", string(respBody), resp.StatusCode)
}
var gqlResp struct {
Data json.RawMessage `json:"data"`
Errors []GraphQLError `json:"errors,omitempty"`
}
if err := json.Unmarshal(respBody, &gqlResp); err != nil {
return nil, lastStatus, fmt.Errorf("failed to parse response: %w (body: %s)", err, string(respBody))
}
if len(gqlResp.Errors) > 0 {
errMsgs := make([]string, len(gqlResp.Errors))
for i, e := range gqlResp.Errors {
errMsgs[i] = e.Message
}
return nil, lastStatus, fmt.Errorf("GraphQL errors: %s", strings.Join(errMsgs, "; "))
}
return gqlResp.Data, lastStatus, nil
}
return nil, lastStatus, fmt.Errorf("max retries (%d) exceeded: %w", MaxRetries+1, lastErr)
}
// FetchIssues retrieves issues from Linear with optional filtering by state.
// state can be: "open" (unstarted/started), "closed" (completed/canceled), or "all".
// If ProjectID is set on the client, only issues from that project are returned.
func (c *Client) FetchIssues(ctx context.Context, state string) ([]Issue, error) {
var allIssues []Issue
var cursor string
filter := map[string]interface{}{
"team": map[string]interface{}{
"id": map[string]interface{}{View on GitHub (pinned to 71377f2769)
Solutions
- Read the joined error messages — GraphQL names the exact invalid field, argument, or ID
- Validate the query against the current Linear GraphQL schema (introspection or their schema docs)
- Check configured team/project ID values are valid Linear UUIDs, not names or slugs
- Verify the API key has access to the requested team/project
- If a field disappeared after a Linear API change, update the query to the renamed field
Example fix
// before: filtering by team name instead of UUID, unsupported by the schema
query := `{ issues(filter: { team: { name: { eq: "Eng" } } }) { nodes { id } } }`
_, err := client.Execute(ctx, &linear.GraphQLRequest{Query: query}) // GraphQL errors: ... 'name' ...
// after: use the team id filter
query := `query($team: String!) { issues(filter: { team: { id: { eq: $team } } }) { nodes { id } } }`
_, err = client.Execute(ctx, &linear.GraphQLRequest{Query: query, Variables: map[string]interface{}{"team": teamUUID}}) Defensive patterns
Strategy: type-guard
Validate before calling
func validateIDs(teamID, projectID string) error {
for name, id := range map[string]string{"team": teamID, "project": projectID} {
if id == "" { continue }
if _, err := uuid.Parse(id); err != nil {
return fmt.Errorf("%s id %q is not a valid UUID", name, id)
}
}
return nil
} Type guard
type GraphQLErrors []struct{ Message string }
func asGraphQLErrors(err error) (msgs []string, ok bool) {
if !strings.HasPrefix(err.Error(), "GraphQL errors: ") { return nil, false }
return strings.Split(strings.TrimPrefix(err.Error(), "GraphQL errors: "), "; "), true
} Try / catch
_, err := client.Execute(ctx, req)
if err != nil {
if msgs, ok := asGraphQLErrors(err); ok {
return fmt.Errorf("linear rejected the query: %v — validate fields/IDs against the current schema", msgs)
}
return err
} Prevention
- Validate query fields against the current Linear GraphQL schema; pin/review after API changes
- Store team/project references as Linear UUIDs, never names or slugs
- Verify the API key can access the requested team/project before batch runs
- Test new queries with a minimal single-item request before running them at scale
When it happens
Trigger: GraphQL validation failures: unknown field/argument names (schema drift after Linear API changes), invalid UUIDs for team/project/issue IDs, missing required variables, or permission errors on resources the API key cannot see. Any Execute() with an invalid query shape produces this.
Common situations: Hand-written GraphQL queries with typos, queries written against an older Linear schema that has since changed, passing empty-string or malformed team/project IDs from config, or querying teams the API key is not a member of.
Related errors
- target is missing required Notion properties: %s
- work item creation failed: %s
- issue update reported as unsuccessful
- metadata validation failed for issue %s: %w
- metadata schema violation: %s
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2cc4c66f353bc87f.
Report an issue: GitHub.