gastownhall/beads · error

remove dep: classify source: %w

Error message

remove dep: classify source: %w

What it means

Wraps a failure of depRepo.WispSourceIDs while RemoveDependencyBySource classifies whether the edge's source issue lives in the wisps table or the regular table. The classification determines which table the delete targets; when the lookup itself fails, the removal is aborted with this wrapper so the caller knows the failure happened before any delete was attempted.

Source

Thrown at internal/storage/domain/dependency.go:352

	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 is
// a wisp while reporting that it was never there (bd-yby99.17). The delete IS
// the verdict, the way the store-backed body reads it off RemoveDependencyInTx
// rather than from a separate lookup.
func (u *dependencyUseCaseImpl) RemoveDependencyBySource(ctx context.Context, sourceID, dependsOnID, actor string) (bool, error) {
	if sourceID == "" || dependsOnID == "" {
		return false, fmt.Errorf("remove dep: sourceID and dependsOnID must not be empty")
	}
	wispSources, err := u.depRepo.WispSourceIDs(ctx, []string{sourceID})
	if err != nil {
		return false, fmt.Errorf("remove dep: classify source: %w", err)
	}
	_, sourceIsWisp := wispSources[sourceID]
	res, err := u.depRepo.Delete(ctx, sourceID, dependsOnID, actor, DepInsertOpts{UseWispsTable: sourceIsWisp, EmitEvent: true})
	if err != nil {
		return false, fmt.Errorf("remove dep %s -> %s: %w", sourceID, dependsOnID, err)
	}
	return res.Found, nil
}

func (u *dependencyUseCaseImpl) removeDep(ctx context.Context, sourceID, dependsOnID, actor string, useWisp bool) error {
	if sourceID == "" || dependsOnID == "" {
		return fmt.Errorf("remove dep: sourceID and dependsOnID must not be empty")
	}
	if _, err := u.depRepo.Delete(ctx, sourceID, dependsOnID, actor, DepInsertOpts{UseWispsTable: useWisp, EmitEvent: true}); err != nil {
		return fmt.Errorf("remove dep %s -> %s: %w", sourceID, dependsOnID, err)
	}
	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix the underlying repository error surfaced by %w (connectivity, SQL, context).
  2. Confirm the database schema is current (bd doctor / migration status) since wisp classification reads the wisps table.
  3. Retry the removal once storage is healthy — no delete has run yet, so it is safe to re-invoke.
  4. If timeouts are the cause, increase the context deadline for large batch scripts.

Example fix

// before: assuming removal failed because the edge was missing
removed, err := uc.RemoveDependencyBySource(ctx, src, dst, actor)
if err != nil {
    log.Println("edge not found")
}
// after: distinguish classification failure from not-found
removed, err := uc.RemoveDependencyBySource(ctx, src, dst, actor)
if err != nil {
    log.Printf("removal aborted before delete: %v", err) // storage issue
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-verify storage reachability before batch removal
if err := db.PingContext(ctx); err != nil {
    return fmt.Errorf("storage unreachable, aborting removals: %w", err)
}

Try / catch

_, err := uc.RemoveDependencyBySource(ctx, src, dst, actor)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
        return retryWithLongerDeadline()
    }
    return fmt.Errorf("classification/read failure, nothing deleted: %w", err)
}

Prevention

When it happens

Trigger: RemoveDependencyBySource calls WispSourceIDs(ctx, []string{sourceID}) and the repo query fails — DB unreachable, SQL error, context canceled, or Dolt transaction/lock error while scanning the wisps classification.

Common situations: Database connection dropped mid-command; context deadline exceeded during batch removals; Dolt server error or schema mismatch after a version upgrade; read-only replica used for the classification query.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/e4dcd403d4e6417a. Report an issue: GitHub.