gastownhall/beads · error

db: DependencySQLRepository.Insert: dep must not be nil

Error message

db: DependencySQLRepository.Insert: dep must not be nil

What it means

DependencySQLRepository.Insert returns this error when the dep argument is nil. It is the first of several defensive guards in Insert validating the dependency record before any SQL write. A nil dependency carries no IssueID/DependsOnID so it can never be persisted.

Source

Thrown at internal/storage/domain/db/dependency.go:73

		return "depends_on_external", nil
	}
	var probe int
	err := r.runner.QueryRowContext(ctx, "SELECT 1 FROM wisps WHERE id = ? LIMIT 1", dependsOnID).Scan(&probe)
	switch {
	case err == nil:
		return "depends_on_wisp_id", nil
	case errors.Is(err, sql.ErrNoRows):
		return "depends_on_issue_id", nil
	case dberrors.IsTableNotExist(err):
		return "depends_on_issue_id", nil
	default:
		return "", fmt.Errorf("classify dep target %s: %w", dependsOnID, err)
	}
}

func (r *dependencySQLRepositoryImpl) Insert(ctx context.Context, dep *types.Dependency, actor string, opts domain.DepInsertOpts) error {
	if dep == nil {
		return errors.New("db: DependencySQLRepository.Insert: dep must not be nil")
	}
	if dep.IssueID == "" {
		return errors.New("db: DependencySQLRepository.Insert: IssueID must not be empty")
	}
	if dep.DependsOnID == "" {
		return errors.New("db: DependencySQLRepository.Insert: DependsOnID must not be empty")
	}
	if dep.IssueID == dep.DependsOnID {
		// Lead with the sentinel so this defensive repo-layer guard renders like
		// every other self-dep site ("cannot add self-dependency: X cannot depend
		// on itself") instead of appending the sentinel text.
		return fmt.Errorf("db: DependencySQLRepository.Insert: %w: %s cannot depend on itself", domain.ErrSelfDependency, dep.IssueID)
	}

	metadata := dep.Metadata
	if metadata == "" {
		metadata = "{}"
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check dep != nil at the call site before invoking Insert.
  2. Fix the upstream construction path so a valid *types.Dependency is always built.
  3. If the dependency is legitimately absent, skip the Insert rather than calling it.

Example fix

// before
var dep *types.Dependency
repo.Insert(ctx, dep, actor, opts) // panics-free but errors
// after
if dep == nil {
    return nil // nothing to insert
}
repo.Insert(ctx, dep, actor, opts)
Defensive patterns

Strategy: validation

Validate before calling

if dep == nil {
    return fmt.Errorf("dependency not initialized")
}

Type guard

func depValid(d *types.Dependency) bool { return d != nil }

Try / catch

if err := repo.Insert(ctx, dep, actor, opts); err != nil {
    if strings.Contains(err.Error(), "dep must not be nil") {
        // skip or construct dependency
    }
}

Prevention

When it happens

Trigger: Calling Insert(ctx, nil, actor, opts) — usually from a caller that built the *types.Dependency conditionally and skipped initialization on some code path, or passed a nil pointer from a map/slice lookup.

Common situations: A lookup that returned nil, nil (not found) and the result was passed to Insert unchecked; optional dependency creation where the dep pointer was left nil.

Related errors


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