{"record":{"id":"7c583d8338f5c9b9","repo":"gastownhall/beads","slug":"failed-to-commit-orphaned-dependency-removals-w","errorCode":null,"errorMessage":"failed to commit orphaned dependency removals: %w","messagePattern":"failed to commit orphaned dependency removals: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/doctor/fix/validation.go","lineNumber":109,"sourceCode":"\t\tcase \"dependencies\":\n\t\t\t_, err = tx.Exec(\"DELETE FROM dependencies WHERE issue_id = ? AND \"+fixDependencyTargetExpr+\" = ?\", o.issueID, o.dependsOnID)\n\t\tcase \"wisp_dependencies\":\n\t\t\t_, err = tx.Exec(\"DELETE FROM wisp_dependencies WHERE issue_id = ? AND \"+fixDependencyTargetExpr+\" = ?\", o.issueID, o.dependsOnID)\n\t\tdefault:\n\t\t\tfmt.Printf(\"  Warning: skipped orphaned dependency from unexpected table %s\\n\", o.depTable)\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"  Warning: failed to remove %s→%s: %v\\n\", o.issueID, o.dependsOnID, err)\n\t\t} else {\n\t\t\tremoved++\n\t\t\tif showIndividual {\n\t\t\t\tfmt.Printf(\"  Removed orphaned dependency: %s→%s\\n\", o.issueID, o.dependsOnID)\n\t\t\t}\n\t\t}\n\t}\n\tif err := tx.Commit(); err != nil {\n\t\treturn fmt.Errorf(\"failed to commit orphaned dependency removals: %w\", err)\n\t}\n\n\t// Commit changes in Dolt\n\t_, _ = db.Exec(\"CALL DOLT_COMMIT('-Am', 'doctor: remove orphaned dependencies')\") // Best effort: commit advisory; schema fix already applied in-memory\n\n\tfmt.Printf(\"  Fixed %d orphaned dependency reference(s)\\n\", removed)\n\treturn nil\n}\n\n// ChildParentDependencies removes child→parent blocking dependencies.\n// These often indicate a modeling mistake (deadlock: child waits for parent, parent waits for children).\n// Requires explicit opt-in via --fix-child-parent flag since some workflows may use these intentionally.\n// If verbose is true, prints each removed dependency; otherwise shows only summary.\nfunc ChildParentDependencies(path string, verbose bool) error {\n\tbeadsDir, err := resolvedWorkspaceBeadsDir(path)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/doctor/fix/validation.go#L91-L127","documentation":"After deleting orphaned dependency rows inside an explicit transaction, OrphanedDependencies calls tx.Commit(). Because Dolt may run with autocommit disabled, this commit is what makes the deletions durable — if it fails, the wrapped error is returned and none of the removals are persisted (the transaction rolls back). This error appears only after individual DELETEs succeeded on the connection.","triggerScenarios":"tx.Commit() fails at validation.go:108 — the connection to the Dolt server dropped during the DELETE loop, the server rejected the commit (e.g. storage error, deadlock/lock wait timeout, server shutting down with --no-auto-commit), or the transaction was already invalidated by an earlier session-level error.","commonSituations":"Dolt server killed mid-fix so buffered writes can't be committed; disk-full or storage backend failure on the server; lock conflicts with another session holding row/table locks on `dependencies`/`wisp_dependencies`; long DELETE loop exceeding a lock-wait timeout before Commit.","solutions":["Re-run `bd doctor --fix` after confirming the Dolt server is healthy — the transaction rolled back, so the fix is safely repeatable.","Check server logs and disk space; resolve storage errors (disk full, corrupted sstables) before retrying.","Ensure no other session holds locks on dependencies/wisp_dependencies (lock wait timeout); close competing bd processes.","If the server runs with --no-auto-commit, verify it accepts explicit commits and isn't in a read-only or shutting-down state."],"exampleFix":"// before: server dropped connection during DELETE loop\nif err := tx.Commit(); err != nil {\n\treturn fmt.Errorf(\"failed to commit orphaned dependency removals: %w\", err)\n}\n// after: restart dolt server, ensure free disk, then re-run the fix\n// dolt server &  # healthy restart; orphan removals are re-applied from scratch\nif err := tx.Commit(); err != nil {\n\treturn fmt.Errorf(\"failed to commit orphaned dependency removals: %w\", err) // succeeds\n}","handlingStrategy":"retry","validationCode":"// check free disk and server health before running deletions\nif err := db.PingContext(ctx); err != nil {\n\treturn fmt.Errorf(\"server unhealthy before fix: %w\", err)\n}\n// and on the host: df -h <dolt_data_dir>","typeGuard":"var lockErr *driver.Error\nif errors.As(err, &lockErr) && (lockErr.Number == 1205 || lockErr.Number == 1213) {\n\t// lock wait timeout / deadlock — wait and retry the fix\n}","tryCatchPattern":"if err := fix.OrphanedDependencies(path, verbose); err != nil {\n\tif strings.Contains(err.Error(), \"failed to commit\") {\n\t\t// transaction rolled back; nothing persisted — safe to re-run\n\t\ttime.Sleep(2 * time.Second)\n\t\terr = fix.OrphanedDependencies(path, verbose)\n\t}\n\tif err != nil {\n\t\tlog.Fatalf(\"orphan removals not committed: %v\", err)\n\t}\n}","preventionTips":["Ensure ample free disk space on the Dolt data directory before large fixes.","Close competing bd processes/sessions to avoid lock-wait timeouts during the DELETE loop.","Run with autocommit semantics understood: with --no-auto-commit servers, only Commit persists, so verify server health beforehand.","Re-run after failure — the transaction rolls back, so the fix is idempotent."],"tags":["go","database","dolt","transaction","commit"],"backgroundTag":"transaction-commit-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}