{"record":{"id":"b702a73fa8661611","repo":"gastownhall/beads","slug":"remove-dependency-w","errorCode":null,"errorMessage":"remove dependency: %w","messagePattern":"remove dependency: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependencies.go","lineNumber":944,"sourceCode":"\t_, _, eventTable, depTable := WispTableRouting(isWisp)\n\n\t// Capture the row's type before deleting so we can dispatch the right\n\t// affected-set helper. If no row matches, treat as a no-op.\n\tvar depType, depMetadata string\n\trow := tx.QueryRowContext(ctx, fmt.Sprintf(\n\t\t`SELECT type, metadata FROM %s WHERE issue_id = ? AND %s = ?`, depTable, DepTargetExpr),\n\t\tissueID, dependsOnID)\n\tif err := row.Scan(&depType, &depMetadata); err != nil {\n\t\tif errors.Is(err, sql.ErrNoRows) {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn false, fmt.Errorf(\"lookup dependency type for %s -> %s: %w\", issueID, dependsOnID, err)\n\t}\n\n\tif _, err := tx.ExecContext(ctx, fmt.Sprintf(\n\t\t`DELETE FROM %s WHERE issue_id = ? AND %s = ?`, depTable, DepTargetExpr),\n\t\tissueID, dependsOnID); err != nil {\n\t\treturn false, fmt.Errorf(\"remove dependency: %w\", err)\n\t}\n\n\t// The lookup above returned early when no row matched, so reaching here means\n\t// an edge was actually deleted. Record the dependency_removed event on the\n\t// source issue's event table for bd CLI / library history observers — but only\n\t// when emitEvent is set, so structural removes stay silent (parity with the\n\t// proxied repo and with the symmetric AddDependencyInTx EmitEvent gate).\n\teventWritten := false\n\tif emitEvent {\n\t\tif err := RecordEventInTable(ctx, tx, eventTable, issueID, types.EventDependencyRemoved, actor,\n\t\t\tfmt.Sprintf(\"Removed dependency on %s\", dependsOnID)); err != nil {\n\t\t\treturn false, fmt.Errorf(\"record dependency_removed event: %w\", err)\n\t\t}\n\t\teventWritten = true\n\t}\n\n\tvar affectedIssues, affectedWisps []string\n\tvar aerr error","sourceCodeStart":926,"sourceCodeEnd":962,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependencies.go#L926-L962","documentation":"This error wraps the DELETE failure in removeDependencyInTx after the edge was positively located. The lookup succeeded (so the edge exists) but the DELETE FROM <depTable> WHERE issue_id=? AND <target>=? statement failed at the driver level, so the dependency was not removed and the whole transaction should roll back.","triggerScenarios":"RemoveDependencyInTx or ApplyParentPatch reaches the DELETE and the driver returns an error — FK RESTRICT from child rows, database locked by a concurrent writer, connection dropped, trigger rejection, or read-only replica.","commonSituations":"Concurrent CLI sessions contending for the SQLite write lock; FK constraints referencing the dependency row from audit tables; attempting writes against a read-only Dolt replica; disk-full during the delete.","solutions":["Read the wrapped driver error: FK violation -> remove referencing rows; locked -> retry after the other writer finishes.","Retry the whole removal transaction; dependency removal is idempotent (a second run sees no rows).","Check for child rows/audit tables with FK references to the dependency edge and clear them.","Verify you are connected to a writable primary, not a read-only replica."],"exampleFix":"// before: delete blocked by FK\nok, err := store.RemoveDependencyInTx(ctx, tx, \"bd-1\", \"bd-2\", actor, true)\n// after: remove referencing snapshot rows first, then retry\n tx.Exec(\"DELETE FROM dep_snapshots WHERE issue_id=? AND depends_on_id=?\", \"bd-1\", \"bd-2\")\nok, err = store.RemoveDependencyInTx(ctx, tx, \"bd-1\", \"bd-2\", actor, true)","handlingStrategy":"retry","validationCode":"// precheck: writable primary and no child FK rows blocking the delete\nvar count int\nif err := db.QueryRow(\"SELECT COUNT(*) FROM dep_snapshots WHERE issue_id=? AND depends_on_id=?\", issueID, dependsOnID).Scan(&count); err != nil {\n    return err\n}\nif count > 0 { return fmt.Errorf(\"clear %d referencing rows first\", count) }","typeGuard":"func isDepDeleteFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"remove dependency:\")\n}","tryCatchPattern":"removed, err := store.RemoveDependency(ctx, issueID, dependsOnID, actor)\nif isDepDeleteFailure(err) {\n    if fkViolation(errors.Unwrap(err)) { return fmt.Errorf(\"clear referencing rows, then retry: %w\", err) }\n    if isTransient(errors.Unwrap(err)) { err = withBackoff(3, func() error { _, e := store.RemoveDependency(ctx, issueID, dependsOnID, actor); return e }) }\n}","preventionTips":["Configure adequate busy_timeout / lock wait for concurrent CLI sessions.","Avoid FK-coupled audit tables, or cascade-clean them with the dependency edge.","Write to the primary, never a read-only replica.","Removal is idempotent — safe to retry entire transactions."],"tags":["storage","sql","dependencies","delete"],"backgroundTag":"dependency-remove-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}