{"record":{"id":"755dd4dae976df6d","repo":"gastownhall/beads","slug":"failed-to-close-duplicate-w","errorCode":null,"errorMessage":"failed to close duplicate: %w","messagePattern":"failed to close duplicate: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/duplicate.go","lineNumber":113,"sourceCode":"\tcanonical, err = store.GetIssue(ctx, canonicalID)\n\tif err != nil || canonical == nil {\n\t\treturn fmt.Errorf(\"canonical issue not found: %s\", canonicalID)\n\t}\n\n\t// Add a \"duplicates\" dependency edge (duplicate → canonical)\n\tdep := &types.Dependency{\n\t\tIssueID:     duplicateID,\n\t\tDependsOnID: canonicalID,\n\t\tType:        types.DepDuplicates,\n\t}\n\tif err := store.AddDependency(ctx, dep, actor); err != nil {\n\t\treturn fmt.Errorf(\"failed to add duplicate link: %w\", err)\n\t}\n\n\t// Close the duplicate issue through the lifecycle operation so it records\n\t// the complete closure state.\n\tif err := store.CloseIssue(ctx, duplicateID, \"\", actor, \"\"); err != nil {\n\t\treturn fmt.Errorf(\"failed to close duplicate: %w\", err)\n\t}\n\n\tcommandDidWrite.Store(true)\n\n\tif isJSONOutput() {\n\t\treturn outputJSON(map[string]interface{}{\n\t\t\t\"duplicate\": duplicateID,\n\t\t\t\"canonical\": canonicalID,\n\t\t\t\"status\":    \"closed\",\n\t\t})\n\t}\n\n\tfmt.Printf(\"%s Marked %s as duplicate of %s (closed)\\n\", ui.RenderPass(\"✓\"), duplicateID, canonicalID)\n\treturn nil\n}\n\nfunc runSupersede(cmd *cobra.Command, args []string) error {\n\tif usesProxiedServer() {","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/duplicate.go#L95-L131","documentation":"Wraps store.CloseIssue failure after the dependency edge was successfully added in runDuplicate. The duplicate link exists but the lifecycle close of the duplicate issue failed, leaving the issue in an inconsistent intermediate state (linked but still open). Because the dep was already written, retrying is safe — the same 'duplicates' edge is idempotent in practice or the command should be re-run carefully.","triggerScenarios":"CloseIssue returns an error: issue already closed with a conflicting state, storage write failure, validation of closure fields rejected, or a driver error mid-transaction.","commonSituations":"A concurrent process closed the issue first; DB lock/timeout during the close write; store-level lifecycle validation failure; disk full during the write.","solutions":["Check the issue state with `bd show <duplicate-id>` — it may already be closed; if so, nothing else is needed","If still open, re-run `bd duplicate` (edge addition is tolerated) or `bd close <duplicate-id>` directly","Check storage health if write errors persist","Resolve concurrency: ensure no other agent is closing the same issue simultaneously"],"exampleFix":"// before\nError: failed to close duplicate: storage write failed\n$ bd show bd-42  # still open\n// after\n$ bd close bd-42 --reason \"duplicate of bd-17\"","handlingStrategy":"try-catch","validationCode":"iss, err := store.GetIssue(ctx, duplicateID)\nif err != nil { return err }\nif iss.Status == types.StatusClosed { return nil } // already closed, nothing to do","typeGuard":null,"tryCatchPattern":"if err := store.CloseIssue(ctx, duplicateID, \"\", actor, \"\"); err != nil {\n    if iss, gerr := store.GetIssue(ctx, duplicateID); gerr == nil && iss.Status == types.StatusClosed {\n        return nil // already closed concurrently; treat as success\n    }\n    return fmt.Errorf(\"failed to close duplicate: %w\", err)\n}","preventionTips":["Check issue status before closing to tolerate concurrent closes","Serialize duplicate-marking across agents with a lock or bd claim","Retry close once on transient storage errors"],"tags":["storage","lifecycle","duplicate"],"backgroundTag":"issue-close-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}