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

  1. Read the joined error messages — GraphQL names the exact invalid field, argument, or ID
  2. Validate the query against the current Linear GraphQL schema (introspection or their schema docs)
  3. Check configured team/project ID values are valid Linear UUIDs, not names or slugs
  4. Verify the API key has access to the requested team/project
  5. 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

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


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