{"record":{"id":"81002f0c295d9f85","repo":"gastownhall/beads","slug":"db-dependencysqlrepository-insert-mark-is-blocke-81002f","errorCode":null,"errorMessage":"db: DependencySQLRepository.Insert: mark is_blocked (affected): %w","messagePattern":"db: DependencySQLRepository\\.Insert: mark is_blocked \\(affected\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/dependency.go","lineNumber":222,"sourceCode":"\t}\n\tif aerr != nil {\n\t\treturn fmt.Errorf(\"db: DependencySQLRepository.Insert: affected set: %w\", aerr)\n\t}\n\tif dep.Type == types.DepBlocks || dep.Type == types.DepConditionalBlocks {\n\t\tif err := r.markDirectBlockedSource(ctx, dep.IssueID, srcIsWisp, dep.DependsOnID, targetCol); err != nil {\n\t\t\treturn fmt.Errorf(\"db: DependencySQLRepository.Insert: mark is_blocked: %w\", err)\n\t\t}\n\t\taffectedIssues, affectedWisps = issueops.RemoveSourceFromAffected(dep.IssueID, srcIsWisp, affectedIssues, affectedWisps)\n\t}\n\tif dep.Type == types.DepParentChild {\n\t\tif err := issueops.RecomputeIsBlockedInTx(ctx, r.runner, affectedIssues, affectedWisps); err != nil {\n\t\t\treturn fmt.Errorf(\"db: DependencySQLRepository.Insert: recompute is_blocked: %w\", err)\n\t\t}\n\t\t// Snapshot only after all derived blocked-state maintenance has completed.\n\t\treturn issueops.RecordDepEventInTx(ctx, r.runner, issueops.EventDepAdd, dep.IssueID, string(dep.Type), dep.DependsOnID, metadata, actor)\n\t}\n\tif err := issueops.MarkIsBlockedInTx(ctx, r.runner, affectedIssues, affectedWisps); err != nil {\n\t\treturn fmt.Errorf(\"db: DependencySQLRepository.Insert: mark is_blocked (affected): %w\", err)\n\t}\n\t// Snapshot only after all derived blocked-state maintenance has completed.\n\t// Never gated on opts.EmitEvent: a structurally-wired edge is as real to a\n\t// replaying consumer as one added by an explicit dep verb.\n\treturn issueops.RecordDepEventInTx(ctx, r.runner, issueops.EventDepAdd, dep.IssueID, string(dep.Type), dep.DependsOnID, metadata, actor)\n}\n\n// classifyMissingEndpoint names the endpoint behind a foreign-key refusal,\n// re-read on the same runner that refused the insert. The driver's message\n// names its constraint, but taking identity out of driver prose is the thing a\n// typed refusal exists to avoid, so the two endpoints are read back instead —\n// only on the refusal path, so a bulk add still pays no probe per edge.\n//\n// The refusal is never downgraded to a probe's failure: anything the reads\n// cannot settle returns nil and the caller keeps the original error.\nfunc (r *dependencySQLRepositoryImpl) classifyMissingEndpoint(ctx context.Context, dep *types.Dependency, sourceIsWisp bool, targetCol string, insertErr error) error {\n\tif !dberrors.IsMissingForeignKeyTarget(insertErr) {\n\t\treturn nil","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/dependency.go#L204-L240","documentation":"This error wraps a failure from MarkIsBlockedInTx, the final propagation pass that marks all issues in the affected set as blocked after adding a scheduling (blocks/conditional/waits-for) edge. The edge exists but blocked-state propagation failed, leaving downstream issues potentially stale.","triggerScenarios":"Calling Insert for a non-parent-child scheduling edge where issueops.MarkIsBlockedInTx fails on the affected set — driver error, connection loss, or schema mismatch during the bulk UPDATE.","commonSituations":"Connection dropped mid bulk-update; schema drift; very large affected sets timing out.","solutions":["Retry the operation; same-type inserts are idempotent.","Run a blocked-state recompute/repair to clear stale flags.","Verify schema version with bd doctor / migrate.","Inspect the wrapped driver error for the failing statement."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := repo.Insert(ctx, dep, actor, opts); err != nil {\n    if strings.Contains(err.Error(), \"mark is_blocked (affected)\") {\n        // propagation failed; re-run Insert (idempotent) or run blocked-state repair\n    }\n}","preventionTips":["Retry inserts on transient failure — same-type inserts are idempotent.","Run scheduled is_blocked recomputes.","Migrate schema before upgrading bd."],"tags":["database","is-blocked","propagation"],"backgroundTag":"blocked-state-mark-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}