gastownhall/beads · error

failed to create issue: %w

Error message

failed to create issue: %w

What it means

CreateIssue sends the issueCreate GraphQL mutation and wraps any Execute failure with this message. It distinguishes transport/GraphQL failures from application-level 'creation unsuccessful' responses handled later.

Source

Thrown at internal/linear/client.go:850

	if stateID != "" {
		input["stateId"] = stateID
	}
	if len(labelIDs) > 0 {
		input["labelIds"] = labelIDs
	}
	return input
}

// CreateIssue creates a new issue in Linear.
func (c *Client) CreateIssue(ctx context.Context, title, description string, priority int, stateID string, labelIDs []string) (*Issue, error) {
	req := &GraphQLRequest{
		Query:     issueCreateMutation,
		Variables: map[string]interface{}{"input": c.buildIssueCreateInput(title, description, priority, stateID, labelIDs)},
	}

	data, err := c.Execute(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to create issue: %w", err)
	}

	var createResp IssueCreateResponse
	if err := json.Unmarshal(data, &createResp); err != nil {
		return nil, fmt.Errorf("failed to parse create response: %w", err)
	}

	if !createResp.IssueCreate.Success {
		return nil, fmt.Errorf("issue creation reported as unsuccessful")
	}

	return &createResp.IssueCreate.Issue, nil
}

// createIssueSingleAttempt executes the issueCreate mutation exactly once,
// without the retry loop used by Execute. This is intentional: retrying a
// mutation that may have already reached Linear risks creating a duplicate.
// The caller (CreateIssueIdempotent) handles retry safety by re-searching for

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the root cause to identify transport vs. GraphQL validation errors.
  2. Verify every ID in the input (stateID, labelIDs) is currently valid via the Linear API.
  3. Check the API key validity and scopes.
  4. Retry with backoff on 429 or transient network errors; use CreateIssueIdempotent to avoid duplicates on retry.

Example fix

// before
if err != nil {
    return nil, fmt.Errorf("failed to create issue: %w", err)
}
// after
if err != nil {
    var gqlErr *GraphQLValidationError
    if errors.As(err, &gqlErr) {
        return nil, fmt.Errorf("failed to create issue (input: state=%s labels=%v): %w", stateID, labelIDs, err)
    }
    return nil, fmt.Errorf("failed to create issue: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// validate referenced IDs before the mutation
if stateID != "" && !uuidRegex.MatchString(stateID) {
    return fmt.Errorf("invalid state ID: %q", stateID)
}
for _, id := range labelIDs {
    if !uuidRegex.MatchString(id) {
        return fmt.Errorf("invalid label ID: %q", id)
    }
}

Try / catch

issue, err := client.CreateIssue(ctx, title, desc, pri, stateID, labelIDs)
if err != nil {
    if isRateLimit(err) {
        time.Sleep(backoff); return retry()
    }
    return fmt.Errorf("issue %q not created: %w", title, err)
}

Prevention

When it happens

Trigger: Execute fails during the issueCreate mutation: network timeout, 401 from a bad API key, 429 rate limit, GraphQL validation errors from an invalid input (bad state ID, nonexistent label IDs, missing required fields in the input map), or duplicate-subscription GraphQL errors.

Common situations: Passing stale workflow-state or label UUIDs (deleted since cached), invalid priority enum value, expired API key, network blips during automated `bd`-to-Linear sync runs.

Related errors


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