{"record":{"id":"cc92a685ca121148","repo":"gastownhall/beads","slug":"retarget-inbound-dependencies-to-wisp-in-s-for-s","errorCode":null,"errorMessage":"retarget inbound dependencies to wisp in %s for %s: %w","messagePattern":"retarget inbound dependencies to wisp in (.+?) for (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependencies.go","lineNumber":794,"sourceCode":"\t\treturn nil\n\t}\n\treturn value.Time\n}\n\nfunc RetargetInboundDependenciesToWispInTx(ctx context.Context, tx DBTX, id string) error {\n\tfor _, table := range []string{\"dependencies\", \"wisp_dependencies\"} {\n\t\tif err := checkRetargetTargetCollision(ctx, tx, table, \"depends_on_issue_id\", \"depends_on_wisp_id\", id); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := checkRenameTargetCollision(ctx, tx, table, \"depends_on_wisp_id\", id); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := tx.ExecContext(ctx, fmt.Sprintf(`\n\t\t\tUPDATE %s\n\t\t\tSET depends_on_wisp_id = ?, depends_on_issue_id = NULL\n\t\t\tWHERE depends_on_issue_id = ?\n\t\t`, table), id, id); err != nil {\n\t\t\treturn fmt.Errorf(\"retarget inbound dependencies to wisp in %s for %s: %w\", table, id, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc RetargetInboundDependenciesToIssueInTx(ctx context.Context, tx DBTX, id string) error {\n\tfor _, table := range []string{\"dependencies\", \"wisp_dependencies\"} {\n\t\tif err := checkRetargetTargetCollision(ctx, tx, table, \"depends_on_wisp_id\", \"depends_on_issue_id\", id); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := checkRenameTargetCollision(ctx, tx, table, \"depends_on_issue_id\", id); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := tx.ExecContext(ctx, fmt.Sprintf(`\n\t\t\tUPDATE %s\n\t\t\tSET depends_on_issue_id = ?, depends_on_wisp_id = NULL\n\t\t\tWHERE depends_on_wisp_id = ?\n\t\t`, table), id, id); err != nil {","sourceCodeStart":776,"sourceCodeEnd":812,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependencies.go#L776-L812","documentation":"This error wraps a SQL failure from the UPDATE that rewrites inbound dependency edges pointing at an issue (depends_on_issue_id = id) so they instead point at a wisp (depends_on_wisp_id = id) during an issue-to-wisp move. It is thrown by RetargetInboundDependenciesToWispInTx, which runs the same UPDATE against both the dependencies and wisp_dependencies tables inside the caller's transaction. The wrapped %w carries the underlying driver error (constraint violation, table missing, connection loss, etc.).","triggerScenarios":"Calling MoveIssuePersistenceInTx to convert an issue into a wisp when the UPDATE on 'dependencies' or 'wisp_dependencies' fails — e.g. the database connection drops mid-transaction, a schema version predates the depends_on_wisp_id column, a CHECK/FK constraint rejects the rewrite, or the transaction was already aborted by an earlier error.","commonSituations":"Running bd against an old database that has not been migrated to the wisp/dual-target dependency schema; disk-full or locked SQLite/Dolt database during a move; a manually edited schema missing depends_on_wisp_id; concurrent writers causing lock timeouts mid-move.","solutions":["Read the wrapped driver error (%w) to identify the concrete cause (missing column, constraint, lock, IO).","Run the project's schema migration (bd migrate/upgrade or equivalent) so dependencies and wisp_dependencies have depends_on_wisp_id.","Retry the move once the database is reachable and no other writer holds the lock; the caller's transaction rolls back so state is consistent.","If a constraint rejects the rewrite, remove or resolve the conflicting dependency edge first, then retry the move."],"exampleFix":"// before: move fails against an unmigrated DB\nerr := MoveIssuePersistenceInTx(ctx, tx, issueID)\n// after: ensure schema is current before moving\nif err := store.Migrate(ctx); err != nil { return err }\nerr := MoveIssuePersistenceInTx(ctx, tx, issueID)","handlingStrategy":"try-catch","validationCode":"// before moving issue->wisp, ensure schema supports typed targets\nvar col string\nerr := db.QueryRow(`SELECT depends_on_wisp_id FROM wisp_dependencies LIMIT 1`).Err()\nif err != nil { return fmt.Errorf(\"run migrations first: %w\", err) }","typeGuard":"func isRetargetErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"retarget inbound dependencies to wisp\")\n}","tryCatchPattern":"err := store.MoveIssue(ctx, issueID)\nif err != nil {\n    var DriverErr *store.DBError\n    if errors.As(err, &DriverErr) && isTransient(DriverErr.Unwrap()) {\n        err = retryTx(store.MoveIssue, issueID)\n    }\n    return err\n}","preventionTips":["Run bd migrations as part of every deploy before issuing move/promote commands.","Keep transactions short to avoid lock contention during moves.","Retry whole move transactions on transient driver errors — they are atomic and safe to rerun.","Monitor disk space and DB health before batch issue conversions."],"tags":["storage","sql","dependencies","transaction"],"backgroundTag":"dependency-retarget-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}