gastownhall/beads · error

delete leases: %w

Error message

delete leases: %w

What it means

The function clears leases belonging to the doomed issues with a DELETE FROM leases subquery; a failure is wrapped as "delete leases: %w". It fires when the lease rows cannot be removed inside the transaction.

Source

Thrown at internal/storage/issueops/bulk_ops.go:204

		}
		issueIDs = append(issueIDs, id)
	}
	_ = rows.Close()

	if len(issueIDs) == 0 {
		return 0, nil
	}

	affectedIssues, affectedWisps, aerr := AffectedByDeletionInTx(ctx, tx, issueIDs, nil)
	if aerr != nil {
		return 0, fmt.Errorf("affected by source-repo delete: %w", aerr)
	}

	// Deleted issues hold no leases: clear them while the id set is still
	// joinable (before the issues rows go away).
	if _, err := tx.ExecContext(ctx,
		`DELETE FROM leases WHERE issue_id IN (SELECT id FROM issues WHERE source_repo = ?)`, sourceRepo); err != nil {
		return 0, fmt.Errorf("delete leases: %w", err)
	}

	// Edges are journaled before the rows go, while their source snapshots can
	// still be read.
	if err := RecordDependencyRemovalsForIssuesInTx(ctx, tx, issueIDs); err != nil {
		return 0, fmt.Errorf("journal dependency removals for source-repo delete: %w", err)
	}

	result, err := tx.ExecContext(ctx, `DELETE FROM issues WHERE source_repo = ?`, sourceRepo)
	if err != nil {
		return 0, fmt.Errorf("delete issues: %w", err)
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return 0, fmt.Errorf("rows affected: %w", err)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error (no such table / database is locked / readonly)
  2. Migrate the schema if the leases table is absent
  3. Ensure no other process holds a write lock; retry the transaction after the contention clears
  4. Check filesystem permissions and free space
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure leases table exists and FS is writable before deleting
_, err := db.Exec("SELECT 1 FROM leases LIMIT 1")

Type guard

if errors.Is(err, sqlite.ErrBusy) || strings.Contains(err.Error(), "database is locked") { /* lock contention */ }

Try / catch

if err := DeleteIssuesBySourceRepoInTx(ctx, tx, repo); err != nil {
    if strings.Contains(err.Error(), "delete leases") {
        // check concurrent writers, then retry the transaction
    }
    return err
}

Prevention

When it happens

Trigger: tx.ExecContext on `DELETE FROM leases WHERE issue_id IN (SELECT ...)` fails: leases table missing, database locked by another writer, foreign-key constraint from another table referencing leases, or context canceled.

Common situations: Older schema without a leases table; concurrent process (another bd instance or agent) holding a write lock; disk-full or read-only filesystem surfacing as a driver write error.

Related errors


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