gastownhall/beads · error

GraphQL error: %s

Error message

GraphQL error: %s

What it means

The GraphQL endpoint returned a valid response envelope whose errors array is non-empty, meaning GitLab rejected the query at the GraphQL level. Only the first error's message is surfaced. This is a semantic/authorization/query error, not a transport error — the request reached the server and was evaluated.

Source

Thrown at internal/gitlab/client.go:524

	// GraphQL endpoint is at /api/graphql (not under /api/v4/)
	urlStr := c.BaseURL + "/api/graphql"
	respBody, _, err := c.doRequest(ctx, http.MethodPost, urlStr, body)
	if err != nil {
		return nil, fmt.Errorf("GraphQL request failed: %w", err)
	}

	var result struct {
		Data   json.RawMessage `json:"data"`
		Errors []struct {
			Message string `json:"message"`
		} `json:"errors"`
	}
	if err := json.Unmarshal(respBody, &result); err != nil {
		return nil, fmt.Errorf("failed to parse GraphQL response: %w", err)
	}
	if len(result.Errors) > 0 {
		return nil, fmt.Errorf("GraphQL error: %s", result.Errors[0].Message)
	}
	return result.Data, nil
}

// WorkItem represents a GitLab work item from the GraphQL API.
type WorkItem struct {
	ID    string `json:"id"`  // Global ID (gid://gitlab/WorkItem/123)
	IID   string `json:"iid"` // Project-scoped ID
	Title string `json:"title"`
	Type  string `json:"type"` // Work item type name
}

// defaultTaskTypeID is the fallback GID for older GitLab instances where the
// workItemTypes GraphQL query is unavailable.
const defaultTaskTypeID = "gid://gitlab/WorkItems::Type/5"

// getTaskWorkItemTypeID returns the GraphQL GID for the "Task" work item type.
// It queries the GitLab instance once per session and caches the result.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the surfaced GraphQL error message — it names the exact problem (field, permission, or resource).
  2. Verify the token's scopes (api/api_scope) and target project permissions.
  3. Check the GitLab version supports the queried GraphQL schema fields (work items require recent versions).
  4. Log all result.Errors, not just [0], when multiple errors are returned.

Example fix

// before: only first error shown
return nil, fmt.Errorf("GraphQL error: %s", result.Errors[0].Message)
// after: collect all messages
msgs := make([]string, 0, len(result.Errors))
for _, e := range result.Errors {
    msgs = append(msgs, e.Message)
}
return nil, fmt.Errorf("GraphQL error: %s", strings.Join(msgs, "; "))
Defensive patterns

Strategy: try-catch

Validate before calling

// validate token scope and project access before GraphQL calls
resp, err := http.Get(client.BaseURL + "/api/v4/user" + "?private_token=" + token)
// expect 200; 401/403 means the token will fail GraphQL permissions too

Try / catch

data, err := client.CreateTaskWorkItem(ctx, req)
if err != nil {
    var gqlErr *GitLabGraphQLError
    if errors.As(err, &gqlErr) || strings.Contains(err.Error(), "GraphQL error:") {
        // surface gqlErr message to caller; it names the permission/schema problem
    }
    return err
}

Prevention

When it happens

Trigger: Calls to getTaskWorkItemTypeID, CreateTaskWorkItem, or GetWorkItemGID where the query is invalid (unknown field, e.g. workItem types not enabled), the token lacks permission, or the referenced resource does not exist.

Common situations: Using a personal access token without api scope; querying workItems on a GitLab version where the field doesn't exist (pre-16.x); referencing a project/group ID the token cannot read; typos in GraphQL query fields after an API upgrade.

Related errors


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