gastownhall/beads · error

createMany[%d]: %w

Error message

createMany[%d]: %w

What it means

Wraps any error from the per-issue create call during batch creation (createMany), annotated with the index of the failing item in the params slice. Batch creation is not transactional across items in this wrapper — it returns immediately on the first failure, so earlier issues may already be persisted.

Source

Thrown at internal/storage/domain/issue.go:1088

		}
	}
	return fmt.Errorf("%w: issue ID %s does not match configured prefix %s", storage.ErrPrefixMismatch, id, prefix)
}

func (u *issueUseCaseImpl) CreateIssues(ctx context.Context, params []CreateIssueParams, actor string) (CreateIssuesResult, error) {
	return u.createMany(ctx, params, actor, false)
}

func (u *issueUseCaseImpl) CreateWisps(ctx context.Context, params []CreateIssueParams, actor string) (CreateIssuesResult, error) {
	return u.createMany(ctx, params, actor, true)
}

func (u *issueUseCaseImpl) createMany(ctx context.Context, params []CreateIssueParams, actor string, useWisp bool) (CreateIssuesResult, error) {
	result := CreateIssuesResult{}
	for i := range params {
		r, err := u.create(ctx, params[i], actor, useWisp)
		if err != nil {
			return result, fmt.Errorf("createMany[%d]: %w", i, err)
		}
		result.Issues = append(result.Issues, r.Issue)
	}
	return result, nil
}

func (u *issueUseCaseImpl) ApplyIssueGraph(ctx context.Context, plan GraphPlan, actor string) (GraphApplyResult, error) {
	return u.applyGraph(ctx, plan, actor, false)
}

func (u *issueUseCaseImpl) ApplyWispGraph(ctx context.Context, plan GraphPlan, actor string) (GraphApplyResult, error) {
	return u.applyGraph(ctx, plan, actor, true)
}

func (u *issueUseCaseImpl) applyGraph(ctx context.Context, plan GraphPlan, actor string, useWisp bool) (GraphApplyResult, error) {
	keyToID := make(map[string]string, len(plan.Nodes))
	pendingAssignees := make(map[int]string, len(plan.Nodes))

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the inner error and the index N to identify the exact failing params entry
  2. Fix or drop the offending item at index N and re-run the remaining items
  3. Make creation idempotent (check for existing IDs) to safely retry after partial success
  4. Pre-validate all params (titles, IDs, deps) before calling createMany

Example fix

// before: one bad item aborts the batch mid-way
params := []CreateIssueParams{good1, badDep, good2}
result, err := uc.CreateIssues(ctx, params, actor)
// after: pre-validate each item
for i, p := range params {
    if err := validate(p); err != nil { log.Printf("skipping item %d: %v", i, err); continue }
}
Defensive patterns

Strategy: try-catch

Validate before calling

for i, p := range params {
    if p.Issue.Title == "" || p.Issue.ID == "" {
        return fmt.Errorf("params[%d] missing title or id", i)
    }
    if existing, _ := uc.GetIssue(ctx, p.Issue.ID); existing != nil {
        return fmt.Errorf("params[%d] duplicates existing %s", i, p.Issue.ID)
    }
}

Try / catch

result, err := uc.CreateIssues(ctx, params, actor)
if err != nil {
    var idx int
    if _, scanErr := fmt.Sscanf(err.Error(), "createMany[%d]", &idx); scanErr == nil {
        // resume from params[idx:] after fixing or skipping
        return retryFrom(ctx, params[idx:], actor)
    }
}

Prevention

When it happens

Trigger: Calling CreateIssues (or wisp variant) with a params slice where item i fails u.create for any reason: validation, prefix mismatch, dep insert failure, storage error.

Common situations: Bulk imports where one entry is malformed or duplicates an existing ID; one item referencing a dependency that doesn't exist; partial import state because earlier items succeeded before the failure.

Related errors


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