gastownhall/beads · error

failed to create project: %w

Error message

failed to create project: %w

What it means

CreateProject sends a projectCreate mutation with a ProjectCreateInput (teamIds, name, description, optional state). This error wraps any Execute failure: transport error, HTTP error, or GraphQL error from Linear (validation, permissions, unknown team ID). The project is not created when this fires.

Source

Thrown at internal/linear/client.go:1534

		"teamIds":     []string{c.TeamID},
		"name":        name,
		"description": description,
	}

	if state != "" {
		input["state"] = state
	}

	req := &GraphQLRequest{
		Query: query,
		Variables: map[string]interface{}{
			"input": input,
		},
	}

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

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

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

	return &createResp.ProjectCreate.Project, nil
}

// UpdateProject updates an existing project in Linear.
func (c *Client) UpdateProject(ctx context.Context, projectID string, updates map[string]interface{}) (*Project, error) {
	query := `
		mutation UpdateProject($id: String!, $input: ProjectUpdateInput!) {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the error — GraphQL validation messages name the offending input field.
  2. Confirm the API token has project create permission for the target team.
  3. Verify c.TeamID is a real team in the workspace (via FetchTeams).
  4. If passing state, use only values Linear accepts for ProjectCreateInput (planned, started, completed, canceled...); otherwise omit it.
  5. Retry on transient transport errors; the mutation is not idempotent, so check for a created project before retrying to avoid duplicates.

Example fix

// before
input["state"] = "in-progress" // invalid for ProjectCreateInput
_, err := client.CreateProject(ctx, name, desc, "in-progress")
// after
// omit state or use a valid enum
_, err := client.CreateProject(ctx, name, desc, "") // state omitted when empty
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight before CreateProject
if name == "" || len(name) > 255 {
    return fmt.Errorf("project name required and <=255 chars")
}
if client.TeamID == "" {
    return fmt.Errorf("TeamID not configured; run FetchTeams first")
}
validProjectStates := map[string]bool{"planned":true,"started":true,"completed":true,"canceled":true,"":true}
if !validProjectStates[state] {
    return fmt.Errorf("invalid project state %q", state)
}

Try / catch

project, err := client.CreateProject(ctx, name, desc, state)
if err != nil {
    if strings.Contains(err.Error(), "permission") || strings.Contains(err.Error(), "403") {
        return fmt.Errorf("token lacks project create scope: %w", err)
    }
    if isNetworkErr(err) {
        // check whether the project was actually created before retrying (avoid duplicates)
        return findOrCreateProject(ctx, client, name, desc, state)
    }
    return err
}

Prevention

When it happens

Trigger: c.Execute fails on the mutation: API token lacks project create permission, c.TeamID is invalid or from another workspace, name/description violates Linear validation (length/required), unknown enum value passed as `state`, network failure, or ctx cancellation.

Common situations: Bot token with read-only scopes used in automation; team configured incorrectly so teamIds contains a nonexistent ID; passing state values not accepted by ProjectCreateInput; transient network failure during CI sync jobs.

Related errors


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