gastownhall/beads · error
db: Get %s: %w
Error message
db: Get %s: %w
What it means
This error wraps any unexpected failure from the repository's Get path, adding the issue ID that was being fetched. It is thrown after scanIssue fails with an error other than sql.ErrNoRows (not-found is returned verbatim as sql.ErrNoRows, not wrapped). Callers like Update and Claim rely on Get to load the row before mutating it, so a wrapped driver/scan failure aborts the whole operation.
Source
Thrown at internal/storage/domain/db/issue.go:564
StartedAtWasZero: startedWasZero,
OldIssue: oldIssue,
}, nil
}
func (r *issueSQLRepositoryImpl) Get(ctx context.Context, id string, opts domain.IssueTableOpts) (*types.Issue, error) {
if id == "" {
return nil, errors.New("db: Get: id must not be empty")
}
table := pickIssueTable(opts.UseWispsTable)
//nolint:gosec // G201: table is one of two hardcoded constants
row := r.runner.QueryRowContext(ctx, fmt.Sprintf("SELECT %s FROM %s %s WHERE id = ?",
issueSelectColumns, table, sqlbuild.LeaseJoin(table)), id)
issue, err := scanIssue(row)
if errors.Is(err, sql.ErrNoRows) {
return nil, sql.ErrNoRows
}
if err != nil {
return nil, fmt.Errorf("db: Get %s: %w", id, err)
}
return issue, nil
}
func (r *issueSQLRepositoryImpl) GetByIDs(ctx context.Context, ids []string, opts domain.IssueTableOpts) ([]*types.Issue, error) {
if len(ids) == 0 {
return nil, nil
}
placeholders := make([]string, len(ids))
args := make([]any, len(ids))
for i, id := range ids {
placeholders[i] = "?"
args[i] = id
}
table := pickIssueTable(opts.UseWispsTable)
//nolint:gosec // G201: table is one of two hardcoded constants
q := fmt.Sprintf("SELECT %s FROM %s %s WHERE id IN (%s)",
issueSelectColumns, table, sqlbuild.LeaseJoin(table), strings.Join(placeholders, ","))View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped cause (%w chain) to identify the driver error; fix the underlying DB problem (connection, schema, permissions).
- Verify the DB schema matches the issueSelectColumns the code expects; run any provided migration/doctor command.
- Check connectivity to the Dolt server and retry transient failures (network blips, context timeouts).
- If scanning fails consistently for one issue, inspect that row for data that violates expected column types.
Example fix
// before
issue, err := repo.Get(ctx, id)
if err != nil { return err } // loses ErrNoRows distinction
// after
issue, err := repo.Get(ctx, id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) { return storage.ErrNotFound }
return fmt.Errorf("get issue %s: %w", id, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify connectivity before calling
if err := sqlDB.PingContext(ctx); err != nil { return fmt.Errorf("db unavailable: %w", err) } Try / catch
issue, err := repo.Get(ctx, id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) { return storage.ErrNotFound }
var transient = isTransientDBErr(err) // inspect wrapped cause
if transient { return retry(...) }
return fmt.Errorf("get issue %s: %w", id, err)
} Prevention
- Always distinguish sql.ErrNoRows from wrapped failures via errors.Is.
- Keep DB schema in sync with the library version before upgrading.
- Ping the DB / use health checks before long-running operations.
- Log the full error chain (%w causes) for diagnosis.
When it happens
Trigger: Calling Get, Update, or Claim on issues via IssueSQLRepository when the underlying SELECT (with lease join) fails: driver-level query errors, connection drops, scan/type-mismatch errors, or corrupted rows. Not raised for missing IDs — those surface as sql.ErrNoRows.
Common situations: Database connection dropped mid-operation, schema drift after an upgrade (columns renamed/moved so scanIssue fails), permission changes revoking SELECT on issues, or context cancellation surfacing as a driver error.
Related errors
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3395d84d8f4936c8.
Report an issue: GitHub.