{"record":{"id":"bb9cccd1c77e112d","repo":"gastownhall/beads","slug":"dependency-s-s-is-a-self-dependency","errorCode":null,"errorMessage":"dependency %s -> %s is a self-dependency","messagePattern":"dependency (.+?) -> (.+?) is a self-dependency","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/migration/legacysqlite/reader.go","lineNumber":994,"sourceCode":"\t\t}\n\t\tidentity := commentIdentity{issueID: issueID, author: author, text: text, createdAt: created}\n\t\tif priorID, exists := seenComments[identity]; exists {\n\t\t\treturn fmt.Errorf(\"legacy SQLite comments %d and %d share current import identity\", priorID, id)\n\t\t}\n\t\tseenComments[identity] = id\n\t\tissue.Comments = append(issue.Comments, &types.Comment{ID: strconv.FormatInt(id, 10), IssueID: issueID, Author: author, Text: text, CreatedAt: created})\n\t}\n\treturn comments.Err()\n}\n\nfunc validateDependencyGraph(issues []*types.Issue) error {\n\tscheduling := make(map[string][]string)\n\thierarchy := make(map[string][]string)\n\tvar blocking []*types.Dependency\n\tfor _, issue := range issues {\n\t\tfor _, dep := range issue.Dependencies {\n\t\t\tif dep.IssueID == dep.DependsOnID {\n\t\t\t\treturn fmt.Errorf(\"dependency %s -> %s is a self-dependency\", dep.IssueID, dep.DependsOnID)\n\t\t\t}\n\t\t\tswitch dep.Type {\n\t\t\tcase types.DepBlocks, types.DepConditionalBlocks:\n\t\t\t\tblocking = append(blocking, dep)\n\t\t\t\tscheduling[dep.IssueID] = append(scheduling[dep.IssueID], dep.DependsOnID)\n\t\t\tcase types.DepParentChild:\n\t\t\t\thierarchy[dep.IssueID] = append(hierarchy[dep.IssueID], dep.DependsOnID)\n\t\t\t\tscheduling[dep.IssueID] = append(scheduling[dep.IssueID], dep.DependsOnID)\n\t\t\t}\n\t\t}\n\t}\n\tif hasDirectedCycle(scheduling) {\n\t\treturn fmt.Errorf(\"legacy SQLite dependency graph has a scheduling cycle\")\n\t}\n\tfor _, dep := range blocking {\n\t\tif types.ExtractPrefix(dep.IssueID) == types.ExtractPrefix(dep.DependsOnID) &&\n\t\t\t(reachable(hierarchy, dep.IssueID, dep.DependsOnID) ||\n\t\t\t\treachable(hierarchy, dep.DependsOnID, dep.IssueID)) {","sourceCodeStart":976,"sourceCodeEnd":1012,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/migration/legacysqlite/reader.go#L976-L1012","documentation":"After loading all issues, the reader validates the dependency graph and rejects any dependency whose issue and depends-on IDs are the same. Self-dependencies are meaningless in bd's graph and would poison cycle/hierarchy checks, so migration aborts with the offending pair.","triggerScenarios":"Legacy SQLite dependency row where issue_id equals depends_on_id (id -> id); detected during the per-issue sweep over issue.Dependencies.","commonSituations":"Buggy legacy tooling that let users or scripts depend an issue on itself; manual SQL inserts; restore bugs that rewrote one side of a dependency to the same ID.","solutions":["Delete self-dependency rows in the legacy DB: DELETE FROM dependencies WHERE issue_id = depends_on_id","Audit for other bad rows at the same time: SELECT * FROM dependencies WHERE issue_id = depends_on_id","Re-run migration; recreate any intended link correctly (a self link has no valid replacement)"],"exampleFix":"-- before\n-- row: bd-1 -> bd-1\nDELETE FROM dependencies WHERE issue_id = depends_on_id;\n-- after: no self-dependencies remain","handlingStrategy":"validation","validationCode":"for (const d of legacyDeps) {\n  if (d.issue_id === d.depends_on_id)\n    throw new Error(`self-dependency ${d.issue_id} -> ${d.depends_on_id}`);\n}","typeGuard":"function hasNoSelfDeps(deps) {\n  return deps.every(d => d.issue_id !== d.depends_on_id);\n}","tryCatchPattern":"try { migrateLegacySQLite(dbPath) } catch (e) {\n  if (e.message.includes('is a self-dependency')) {\n    deleteSelfDependencies(dbPath); // WHERE issue_id = depends_on_id\n    retry();\n  } else throw e;\n}","preventionTips":["DELETE rows WHERE issue_id = depends_on_id as a pre-migration cleanup step","Add a CHECK (issue_id <> depends_on_id) constraint to the legacy schema","Audit any custom tooling that writes dependency rows for self-link bugs"],"tags":["migration","sqlite","graph-validation"],"backgroundTag":"self-dependency","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}