gastownhall/beads · error

GraphQL request failed: %w

Error message

GraphQL request failed: %w

What it means

graphqlRequest performs POSTs to the GitLab GraphQL endpoint (/api/graphql) and wraps any transport-level failure from doRequest with this message. It means the HTTP request itself failed — connection refused, TLS error, timeout, or non-reachable server — not a GraphQL-level error. It is the entry point for the work item hierarchy APIs (getTaskWorkItemTypeID, CreateTaskWorkItem, GetWorkItemGID).

Source

Thrown at internal/gitlab/client.go:511

	}

	return &milestone, nil
}

// GraphQL support for work item hierarchy (Issue → Task parent-child).

// graphqlRequest executes a GraphQL query against the GitLab instance.
func (c *Client) graphqlRequest(ctx context.Context, query string, variables map[string]interface{}) (json.RawMessage, error) {
	body := map[string]interface{}{"query": query}
	if len(variables) > 0 {
		body["variables"] = variables
	}

	// 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.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped error (%w chain) to see the underlying cause (connection refused, TLS, timeout).
  2. Verify c.BaseURL is correct and that <BaseURL>/api/graphql is reachable (curl -X POST).
  3. Confirm the GitLab instance supports the GraphQL API and work items (GitLab 16+ for work items).
  4. Check network/proxy configuration and TLS trust for the GitLab host.

Example fix

// before: base URL missing scheme
client := &Client{BaseURL: "gitlab.example.com"}
// after
client := &Client{BaseURL: "https://gitlab.example.com"}
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(client.BaseURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("BaseURL %q must include scheme and host", client.BaseURL)
}
// optionally probe the endpoint
resp, err := http.Post(client.BaseURL+"/api/graphql", "application/json", strings.NewReader("{}"))

Try / catch

data, err := client.CreateTaskWorkItem(ctx, req)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) || strings.Contains(err.Error(), "GraphQL request failed") {
        // retry with backoff or fail fast on config
    }
    return err
}

Prevention

When it happens

Trigger: Any call to getTaskWorkItemTypeID, CreateTaskWorkItem, or GetWorkItemGID where c.doRequest fails: wrong BaseURL, network outage, TLS certificate rejection, authentication middleware rejecting the POST, or the server not exposing /api/graphql (older GitLab versions).

Common situations: Pointing BaseURL at a host that only serves the REST API; running against GitLab instances older than GraphQL work item support; corporate proxies blocking POST to /api/graphql; expired tokens causing middleware-level connection aborts.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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