{"record":{"id":"fc6a82b6ccabd173","repo":"gastownhall/beads","slug":"create-batch-item-d-w","errorCode":null,"errorMessage":"create batch item %d: %w","messagePattern":"create batch item (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/create_batch.go","lineNumber":66,"sourceCode":"\treturn nil\n}\n\n// CreateBatchItemRequest projects one item onto the single-create request the\n// shared preparation and validation speak. Both front doors and both bodies read\n// an item through it, so no item restates CreateRequest's field rules.\nfunc CreateBatchItemRequest(request publicops.CreateBatchRequest, item publicops.BatchCreateItem) publicops.CreateRequest {\n\treturn publicops.CreateRequest{\n\t\tActor:         request.Actor,\n\t\tIssue:         item.Issue,\n\t\tDependencies:  item.Dependencies,\n\t\tForceIDPrefix: request.ForceIDPrefix,\n\t}\n}\n\n// CreateBatchItemError names the item a batch refusal came from. The role\n// promises the index appears in the message and nowhere else.\nfunc CreateBatchItemError(index int, err error) error {\n\treturn fmt.Errorf(\"create batch item %d: %w\", index, err)\n}\n\n// CreateBatchCommitMessage is the history entry a batch records: the caller's\n// own label when it supplied one, otherwise a default naming how much landed.\n//\n// IT NAMES A COUNT AND NEVER AN ID: a create batch's ids are new, there can be\n// hundreds from one file, and an entry naming them all is the diff written twice.\n//\n// An all-ephemeral batch writes only to the dolt-ignored wisp tables, so the\n// store-backed bodies stage nothing and record no entry whatever this returns —\n// but the unit-of-work backend reads \"\" as \"roll this attempt back\", so a\n// wisp-only batch must still hand it a message or the wisps it created are\n// discarded. That is the same trap CloseBatchCommitMessage documents.\nfunc CreateBatchCommitMessage(request publicops.CreateBatchRequest, result publicops.CreateBatchResult) string {\n\tdurable, ephemeral := 0, 0\n\tfor _, issue := range result.Issues {\n\t\tif IsWisp(issue) {\n\t\t\tephemeral++","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/create_batch.go#L48-L84","documentation":"CreateBatchItemError wraps an underlying batch refusal and prefixes it with 'create batch item N:' so the caller knows which item caused the store to refuse the batch. Per its contract the item index appears only in the message, never structured elsewhere. It is a contextual wrapper — the real cause is the wrapped error (extractable via errors.Unwrap or errors.As/Is).","triggerScenarios":"ExecuteCreateBatch hits a per-item failure (validation, duplicate ID, prefix mismatch, etc.) during batch creation; the store wraps that cause with CreateBatchItemError(index, err).","commonSituations":"Importing a JSONL file where one record has a bad field; a batch where a single issue ID collides with an existing issue; mixed valid/invalid items in one atomic batch.","solutions":["Read the wrapped error after 'create batch item N:' to learn the actual refusal and fix the item at that index","Use errors.Is/errors.As on the returned error to match sentinel causes like storage.ErrValidation or storage.ErrAlreadyExists","Retry the whole batch after fixing the offending item; the batch is atomic so nothing partial was written"],"exampleFix":"// before\nif err := ExecuteCreateBatch(ctx, req); err != nil {\n    return err\n}\n// after\nif err := ExecuteCreateBatch(ctx, req); err != nil {\n    var idxErr error\n    if errors.As(err, &idxErr) { /* inspect wrapped cause for item N */ }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := ExecuteCreateBatch(ctx, req)\nif err != nil {\n    var target error\n    if errors.As(err, &target) && errors.Is(target, storage.ErrAlreadyExists) {\n        // handle duplicate named by 'create batch item N:'\n    } else if errors.Is(err, storage.ErrValidation) {\n        // fix item at index parsed from message\n    }\n    return err\n}","preventionTips":["Always errors.Is/errors.As the wrapped cause, never string-match the prefix","Validate items individually with the single-create validation before batching","Keep batches homogeneous in content quality (e.g. pre-validated import rows)"],"tags":["batch-create","error-wrapping","validation"],"backgroundTag":"batch-item-error-index","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}