gastownhall/beads · error

work item creation failed: %s

Error message

work item creation failed: %s

What it means

The workItemCreate mutation executed and returned mutation-level errors in resp.WorkItemCreate.Errors. This is GitLab's business-level rejection of the work item creation (validation, permissions, bad inputs), surfaced with the first error's text.

Source

Thrown at internal/gitlab/client.go:627

	var resp struct {
		WorkItemCreate struct {
			Errors   []string `json:"errors"`
			WorkItem *struct {
				ID     string `json:"id"`
				IID    string `json:"iid"`
				Title  string `json:"title"`
				WebURL string `json:"webUrl"`
				Type   struct {
					Name string `json:"name"`
				} `json:"workItemType"`
			} `json:"workItem"`
		} `json:"workItemCreate"`
	}
	if err := json.Unmarshal(data, &resp); err != nil {
		return nil, fmt.Errorf("failed to parse work item response: %w", err)
	}
	if len(resp.WorkItemCreate.Errors) > 0 {
		return nil, fmt.Errorf("work item creation failed: %s", resp.WorkItemCreate.Errors[0])
	}
	if resp.WorkItemCreate.WorkItem == nil {
		return nil, fmt.Errorf("work item creation returned nil")
	}

	wi := resp.WorkItemCreate.WorkItem
	return &WorkItem{
		ID:    wi.ID,
		IID:   wi.IID,
		Title: wi.Title,
		Type:  wi.Type.Name,
	}, nil
}

// GetWorkItemGID looks up the global ID of a work item by its project-scoped IID.
func (c *Client) GetWorkItemGID(ctx context.Context, projectPath string, iid int) (string, error) {
	query := fmt.Sprintf(`{
		project(fullPath: %q) {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the surfaced error string — GitLab states exactly which input or permission failed.
  2. Re-fetch a fresh workItemTypeID via getTaskWorkItemTypeID instead of caching it across upgrades.
  3. Verify the token's user has at least Developer role on the target project.
  4. Validate inputs (title non-empty, valid project path) before calling the mutation.

Example fix

// before: caching type ID across versions
workItemTypeID := cachedTypeID // stale after upgrade
// after
workItemTypeID, err := client.getTaskWorkItemTypeID(ctx)
if err != nil {
    return nil, err
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight: verify project access and fresh type ID
if _, err := client.GetProject(ctx, projectPath); err != nil {
    return fmt.Errorf("cannot access project %s: %w", projectPath, err)
}
typeID, err := client.getTaskWorkItemTypeID(ctx)
if err != nil {
    return err
}

Try / catch

item, err := client.CreateTaskWorkItem(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "work item creation failed") {
        // mutation-level rejection: fix the input or permissions named in the message
    }
    return err
}

Prevention

When it happens

Trigger: Calling CreateTaskWorkItem with an invalid title/description, a nonexistent or unauthorized project/namespace, a workItemTypeID that doesn't exist on the instance, or missing widget inputs the mutation requires.

Common situations: A stale cached workItemTypeID after a GitLab upgrade changed type IDs; creating tasks in a project where the token's user lacks Developer+ role; violating title length or description validation rules; using a group ID where a project ID is required.

Related errors


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