gastownhall/beads · error
db: LabelSQLRepository.DeleteAllForIDs from %s: %w
Error message
db: LabelSQLRepository.DeleteAllForIDs from %s: %w
What it means
LabelSQLRepository.DeleteAllForIDs failed to execute its DELETE for one of the target label tables. The repository returns the running total alongside the wrapped driver error. Note the wisps-table 'table not exist' case is treated as success, so this error is a real DELETE failure for a table that does exist (or a non-wisps table).
Source
Thrown at internal/storage/domain/db/label.go:218
if end > len(ids) {
end = len(ids)
}
batch := ids[start:end]
placeholders := make([]string, len(batch))
args := make([]any, len(batch))
for i, id := range batch {
placeholders[i] = "?"
args[i] = id
}
//nolint:gosec // G201: table is one of two hardcoded constants; ? placeholders only.
res, err := r.runner.ExecContext(ctx,
fmt.Sprintf("DELETE FROM %s WHERE issue_id IN (%s)", table, strings.Join(placeholders, ",")),
args...)
if err != nil {
if opts.UseWispsTable && dberrors.IsTableNotExist(err) {
return total, nil
}
return total, fmt.Errorf("db: LabelSQLRepository.DeleteAllForIDs from %s: %w", table, err)
}
n, err := res.RowsAffected()
if err != nil {
return total, fmt.Errorf("db: LabelSQLRepository.DeleteAllForIDs rows affected: %w", err)
}
total += int(n)
}
return total, nil
}
func (r *labelSQLRepositoryImpl) CountAllForIDs(ctx context.Context, ids []string, opts domain.LabelOpts) (int, error) {
if len(ids) == 0 {
return 0, nil
}
table := "labels"
if opts.UseWispsTable {
table = "wisp_labels"
}View on GitHub (pinned to 71377f2769)
Solutions
- Unwrap the error to see the driver cause (no such table, locked, too many params)
- Run schema migrations so the labels table exists before deleting
- Batch the ids slice if the IN-clause exceeds driver parameter limits
- Check for concurrent writers/locks on the database and retry when idle
Example fix
// before
n, err := repo.DeleteAllForIDs(ctx, allIDs, opts)
// after
for i := 0; i < len(allIDs); i += 500 {
if _, err := repo.DeleteAllForIDs(ctx, allIDs[i:min(i+500, len(allIDs))], opts); err != nil { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// ensure table exists and batch ids
if len(ids) == 0 { return 0, nil }
for start := 0; start < len(ids); start += 500 { _ = ids[start:min(start+500, len(ids))] } Try / catch
n, err := repo.DeleteAllForIDs(ctx, ids, opts)
if err != nil {
if dberrors.IsTableNotExist(errors.Unwrap(err)) && opts.UseWispsTable {
return 0, nil // treat as no-op
}
return err
} Prevention
- Run migrations so labels tables exist before deletes
- Batch ID slices under parameter limits
- Avoid concurrent writers contending for locks
- Unwrap and log the driver cause for diagnostics
When it happens
Trigger: Calling DeleteAllForIDs when the DELETE statement fails: table missing in non-wisps mode, SQL error, connection failure, or lock conflict.
Common situations: Schema migrations not run so the labels table is absent; database locked by another writer; too many IDs generating too many placeholders; storage file corruption in embedded mode.
Related errors
- failed to begin transaction: %w
- failed to recompute is_blocked: %w
- failed to commit is_blocked repairs: %w
- failed to query orphaned dependencies: %w
- row iteration error: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7c2835a768338e2d.
Report an issue: GitHub.