{"record":{"id":"d76268909eee1c4c","repo":"gastownhall/beads","slug":"add-dep-insert-w","errorCode":null,"errorMessage":"add dep: insert: %w","messagePattern":"add dep: insert: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/dependency.go","lineNumber":324,"sourceCode":"\n\tif err := u.depRepo.Insert(ctx, dep, actor, DepInsertOpts{UseWispsTable: useWisp, HierarchyValidated: true, CycleValidated: true, EmitEvent: true}); err != nil {\n\t\t// The retype conflict is a user-facing error whose message already\n\t\t// matches embedded verbatim; pass it through unwrapped so the CLI does\n\t\t// not prepend \"add dep: insert:\" (#4547 F-1). The endpoint-existence\n\t\t// refusals are here for the same reason.\n\t\tvar conflict *DependencyTypeConflictError\n\t\tif errors.As(err, &conflict) {\n\t\t\treturn err\n\t\t}\n\t\tvar hierarchyConflict *DependencyHierarchyConflictError\n\t\tif errors.As(err, &hierarchyConflict) {\n\t\t\treturn err\n\t\t}\n\t\tvar missingEndpoint *DependencyEndpointNotFoundError\n\t\tif errors.As(err, &missingEndpoint) {\n\t\t\treturn err\n\t\t}\n\t\treturn fmt.Errorf(\"add dep: insert: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (u *dependencyUseCaseImpl) RemoveDependency(ctx context.Context, issueID, dependsOnID, actor string) error {\n\treturn u.removeDep(ctx, issueID, dependsOnID, actor, false)\n}\n\nfunc (u *dependencyUseCaseImpl) RemoveWispDependency(ctx context.Context, wispID, dependsOnID, actor string) error {\n\treturn u.removeDep(ctx, wispID, dependsOnID, actor, true)\n}\n\n// RemoveDependencyBySource removes one edge from the plane its SOURCE lives in\n// and reports whether there was an edge to remove.\n//\n// It is the source-routed twin of AddDependencies, and exists for the same\n// reason: `bd dep remove` takes whatever id the caller names, and pinning the\n// removal to the durable table means failing to remove an edge whose source is","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/dependency.go#L306-L342","documentation":"Wraps a repository Insert failure when persisting a new dependency edge after hierarchy and cycle validation already passed. Sentinels the caller is expected to see directly (DependencyTypeConflictError, DependencyHierarchyConflictError, DependencyEndpointNotFoundError) are passed through unwrapped; anything else — SQL errors, connection failures, constraint violations — is wrapped with this prefix so the failure point is identifiable.","triggerScenarios":"AddDependency or AddWispDependency reaches depRepo.Insert after validation succeeds, but the insert fails: DB connection lost between validate and write, unique/PK constraint hit on the dependencies row, Dolt transaction conflict, or context cancellation during the write.","commonSituations":"Two processes adding the same edge concurrently; database went read-only or disk full; interrupted Dolt transaction during a sync; stale connection pool after the DB server restarted mid-command.","solutions":["Read the wrapped cause to identify the storage-level failure (constraint, connection, transaction).","Check whether the edge already exists (duplicate insert) before re-adding; delete or update instead.","Verify the DB is writable and both endpoint issues exist; retry once the backend is healthy.","For concurrency, serialize add operations per issue or retry idempotently — the insert is guarded by validation flags so a retry is safe."],"exampleFix":"// before: treating insert failure as a validation problem\nif err := uc.AddDependency(ctx, dep, actor); err != nil {\n    return fmt.Errorf(\"invalid dependency: %w\", err)\n}\n// after: distinguish passed-through sentinels from storage failures\nif err := uc.AddDependency(ctx, dep, actor); err != nil {\n    var conflict *domain.DependencyTypeConflictError\n    if errors.As(err, &conflict) {\n        return err // user-facing validation message\n    }\n    return fmt.Errorf(\"storage insert failed: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"var exists bool\nif err := db.QueryRowContext(ctx,\n    `SELECT COUNT(*) FROM dependencies WHERE issue_id=? AND depends_on_id=?`,\n    dep.IssueID, dep.DependsOnID).Scan(&exists == nil, &exists); err == nil && exists {\n    return nil // edge already present; skip insert\n}","typeGuard":"func isDepConflict(err error) bool {\n    var conflict *domain.DependencyTypeConflictError\n    var hier *domain.DependencyHierarchyConflictError\n    var missing *domain.DependencyEndpointNotFoundError\n    return errors.As(err, &conflict) || errors.As(err, &hier) || errors.As(err, &missing)\n}","tryCatchPattern":"if err := uc.AddDependency(ctx, dep, actor); err != nil {\n    if isDepConflict(err) {\n        return err // user-facing validation, handle distinctly\n    }\n    // otherwise it is \"add dep: insert: ...\" — a storage failure\n    return fmt.Errorf(\"storage failure adding dep: %w\", err)\n}","preventionTips":["Check for an existing edge before inserting (idempotent add)","Avoid concurrent writers on the same issues' dependencies","Ensure the DB is writable and has disk space before bulk operations","Match errors.As on the pass-through sentinel types to avoid misclassifying storage errors"],"tags":["go","storage","insert","dependency-graph"],"backgroundTag":"dependency-insert-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}