gastownhall/beads · error

db: DependencySQLRepository.Delete: lookup type %s -> %s: %w

Error message

db: DependencySQLRepository.Delete: lookup type %s -> %s: %w

What it means

This error wraps a failure from the type-lookup SELECT at the start of DependencySQLRepository.Delete, which reads the existing edge's type and metadata before deleting. A missing edge is handled gracefully (Found:false); this error means the lookup query itself failed.

Source

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

}

func (r *dependencySQLRepositoryImpl) Delete(ctx context.Context, issueID, dependsOnID, actor string, opts domain.DepInsertOpts) (domain.DepDeleteResult, error) {
	if issueID == "" || dependsOnID == "" {
		return domain.DepDeleteResult{}, errors.New("db: DependencySQLRepository.Delete: issueID and dependsOnID must not be empty")
	}
	table := pickDepTable(opts.UseWispsTable)

	var depType, depMetadata string
	//nolint:gosec // G201: table and depTargetExpr are hardcoded constants
	err := r.runner.QueryRowContext(ctx,
		fmt.Sprintf("SELECT type, metadata FROM %s WHERE issue_id = ? AND %s = ?", table, depTargetExpr),
		issueID, dependsOnID,
	).Scan(&depType, &depMetadata)
	switch {
	case errors.Is(err, sql.ErrNoRows):
		return domain.DepDeleteResult{Found: false}, nil
	case err != nil:
		return domain.DepDeleteResult{}, fmt.Errorf("db: DependencySQLRepository.Delete: lookup type %s -> %s: %w", issueID, dependsOnID, err)
	}

	//nolint:gosec // G201: table and depTargetExpr are hardcoded constants
	if _, err := r.runner.ExecContext(ctx,
		fmt.Sprintf("DELETE FROM %s WHERE issue_id = ? AND %s = ?", table, depTargetExpr),
		issueID, dependsOnID,
	); err != nil {
		return domain.DepDeleteResult{}, fmt.Errorf("db: DependencySQLRepository.Delete: %s -> %s: %w", issueID, dependsOnID, err)
	}

	// The type lookup above returned Found:false when no edge existed, so reaching
	// here means a row was deleted — record the dependency_removed event on the
	// source's event table, matching the embedded/issueops RemoveDependencyInTx path.
	// Gated on EmitEvent so only the explicit `bd dep remove` verb emits.
	if opts.EmitEvent {
		if err := r.events.Record(ctx, domain.Event{
			IssueID:  issueID,
			Type:     types.EventDependencyRemoved,

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check DB connectivity and retry.
  2. Verify the dependencies/wisp_dependencies tables exist in the current schema.
  3. Confirm you are targeting the correct storage plane (issues vs wisps).
  4. Inspect the wrapped driver error for the underlying cause.
Defensive patterns

Strategy: retry

Validate before calling

// pre-check the edge exists before Delete
var depType string
err := db.QueryRow("SELECT type FROM dependencies WHERE issue_id=? AND depends_on_id=?", issueID, dependsOnID).Scan(&depType)
if errors.Is(err, sql.ErrNoRows) {
    return // nothing to delete
}

Try / catch

res, err := repo.Delete(ctx, issueID, dependsOnID)
if err != nil {
    if strings.Contains(err.Error(), "lookup type") {
        // lookup failed: check connectivity/table existence, retry
    }
}

Prevention

When it happens

Trigger: Calling Delete(issueID, dependsOnID) where the SELECT type/metadata for the edge fails with a driver error other than ErrNoRows — connection failure, missing table, permission denied.

Common situations: Database unavailable or mid-migration; wrong table due to wisp vs issue plane confusion; revoked SELECT privileges.

Related errors


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