{"record":{"id":"e84fbba4e16bdec9","repo":"gastownhall/beads","slug":"failed-to-link-digest-to-root-w","errorCode":null,"errorMessage":"failed to link digest to root: %w","messagePattern":"failed to link digest to root: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/mol_squash.go","lineNumber":309,"sourceCode":"\t\tSquashedIDs:   childIDs,\n\t\tSquashedCount: len(children),\n\t\tKeptChildren:  keepChildren,\n\t}\n\n\t// Create digest issue\n\tif err := w.CreateIssue(ctx, digestIssue, actorName); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create digest issue: %w\", err)\n\t}\n\tresult.DigestID = digestIssue.ID\n\n\t// Link digest to root as parent-child\n\tdep := &types.Dependency{\n\t\tIssueID:     digestIssue.ID,\n\t\tDependsOnID: root.ID,\n\t\tType:        types.DepParentChild,\n\t}\n\tif err := w.AddDependency(ctx, dep, actorName); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to link digest to root: %w\", err)\n\t}\n\n\t// Delete ephemeral children within the same transaction\n\tif !keepChildren {\n\t\tfor _, id := range childIDs {\n\t\t\tif err := w.DeleteIssue(ctx, id, actorName); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to delete child %s: %w\", id, err)\n\t\t\t}\n\t\t\tresult.DeletedCount++\n\t\t}\n\t}\n\n\t// Auto-close the root if it's a wisp — squash completes the molecule lifecycle\n\tif root.Ephemeral {\n\t\treason := fmt.Sprintf(\"Squashed: %d steps → digest %s\", len(children), result.DigestID)\n\t\tif err := w.CloseIssue(ctx, root.ID, reason, actorName); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to close wisp root %s: %w\", root.ID, err)\n\t\t}","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/mol_squash.go#L291-L327","documentation":"After creating the digest issue, squash links it to the molecule root via a DepParentChild dependency. If w.AddDependency fails, the error is wrapped as 'failed to link digest to root: %w'. The transaction aborts and all squash changes roll back.","triggerScenarios":"bd mol squash when the parent-child dependency insert fails: dependency constraint violations, missing root/digest rows (deleted concurrently), storage write error, or database lock.","commonSituations":"Another process deleted the root between lookup and write; dependency table schema mismatch; DB locked by a concurrent squash or sync.","solutions":["Inspect the wrapped cause to identify constraint vs storage failure","Ensure no concurrent bd process is mutating the same molecule; retry after it finishes","Verify the root issue still exists and the digest was created in the same transaction (it is, so suspect storage-level faults)","Run bd doctor and retry once storage is healthy"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Confirm root still exists immediately before squash\nroot, err := s.GetIssue(ctx, rootID)\nif err != nil || root == nil {\n    return fmt.Errorf(\"root %s no longer exists\", rootID)\n}","typeGuard":null,"tryCatchPattern":"if err := squashAndReport(...); err != nil {\n    if strings.Contains(err.Error(), \"failed to link digest to root\") {\n        log.Printf(\"dependency link failed; squash rolled back: %v\", errors.Unwrap(err))\n    }\n    return err\n}","preventionTips":["Serialize molecule mutations through a single bd session","Do not delete molecule roots while a squash is running","Keep dependency schema current via bd doctor / migrations"],"tags":["go","storage","dependency","transaction"],"backgroundTag":"dependency-write-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}