gastownhall/beads · error
add dep: insert: %w
Error message
add dep: insert: %w
What it means
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.
Source
Thrown at internal/storage/domain/dependency.go:324
if err := u.depRepo.Insert(ctx, dep, actor, DepInsertOpts{UseWispsTable: useWisp, HierarchyValidated: true, CycleValidated: true, EmitEvent: true}); err != nil {
// The retype conflict is a user-facing error whose message already
// matches embedded verbatim; pass it through unwrapped so the CLI does
// not prepend "add dep: insert:" (#4547 F-1). The endpoint-existence
// refusals are here for the same reason.
var conflict *DependencyTypeConflictError
if errors.As(err, &conflict) {
return err
}
var hierarchyConflict *DependencyHierarchyConflictError
if errors.As(err, &hierarchyConflict) {
return err
}
var missingEndpoint *DependencyEndpointNotFoundError
if errors.As(err, &missingEndpoint) {
return err
}
return fmt.Errorf("add dep: insert: %w", err)
}
return nil
}
func (u *dependencyUseCaseImpl) RemoveDependency(ctx context.Context, issueID, dependsOnID, actor string) error {
return u.removeDep(ctx, issueID, dependsOnID, actor, false)
}
func (u *dependencyUseCaseImpl) RemoveWispDependency(ctx context.Context, wispID, dependsOnID, actor string) error {
return u.removeDep(ctx, wispID, dependsOnID, actor, true)
}
// RemoveDependencyBySource removes one edge from the plane its SOURCE lives in
// and reports whether there was an edge to remove.
//
// It is the source-routed twin of AddDependencies, and exists for the same
// reason: `bd dep remove` takes whatever id the caller names, and pinning the
// removal to the durable table means failing to remove an edge whose source isView on GitHub (pinned to 71377f2769)
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.
Example fix
// before: treating insert failure as a validation problem
if err := uc.AddDependency(ctx, dep, actor); err != nil {
return fmt.Errorf("invalid dependency: %w", err)
}
// after: distinguish passed-through sentinels from storage failures
if err := uc.AddDependency(ctx, dep, actor); err != nil {
var conflict *domain.DependencyTypeConflictError
if errors.As(err, &conflict) {
return err // user-facing validation message
}
return fmt.Errorf("storage insert failed: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
var exists bool
if err := db.QueryRowContext(ctx,
`SELECT COUNT(*) FROM dependencies WHERE issue_id=? AND depends_on_id=?`,
dep.IssueID, dep.DependsOnID).Scan(&exists == nil, &exists); err == nil && exists {
return nil // edge already present; skip insert
} Type guard
func isDepConflict(err error) bool {
var conflict *domain.DependencyTypeConflictError
var hier *domain.DependencyHierarchyConflictError
var missing *domain.DependencyEndpointNotFoundError
return errors.As(err, &conflict) || errors.As(err, &hier) || errors.As(err, &missing)
} Try / catch
if err := uc.AddDependency(ctx, dep, actor); err != nil {
if isDepConflict(err) {
return err // user-facing validation, handle distinctly
}
// otherwise it is "add dep: insert: ..." — a storage failure
return fmt.Errorf("storage failure adding dep: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- loading proto: %w
- add dep: cycle check: %w
- remove dep: classify source: %w
- remove dep %s -> %s: %w
- reparent: list current parent: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d76268909eee1c4c.
Report an issue: GitHub.