gastownhall/beads · error
read status from %s: %w
Error message
read status from %s: %w
What it means
Beads throws this when reading the status of an id for the already-closed check fails with a non-'no rows' error on one of the probed tables (issues, then wisps). Missing optional wisp tables are skipped; missing rows just continue the probe; any other error is wrapped with the table name and aborts the close policy evaluation.
Source
Thrown at internal/storage/issueops/close.go:312
for _, target := range []struct {
table string
column string
}{
{table: "issues", column: "depends_on_issue_id"},
{table: "wisps", column: "depends_on_wisp_id"},
} {
var status string
err := tx.QueryRowContext(ctx, "SELECT status FROM "+target.table+" WHERE id = ?", id).Scan(&status)
if err == nil {
return types.Status(status) == types.StatusClosed, target.column, true, nil
}
if errors.Is(err, sql.ErrNoRows) {
continue
}
if optionalBlockedTable(target.table) && isTableNotExistError(err) {
continue
}
return false, "", false, fmt.Errorf("read status from %s: %w", target.table, err)
}
return false, "", false, nil
}
//nolint:gosec // G201: table names come from WispTableRouting (hardcoded constants)
func closeIssueInTx(ctx context.Context, tx DBTX, id string, reason, actor, session string, recordEvent bool) (*CloseResult, error) {
isWisp := IsActiveWispInTx(ctx, tx, id)
issueTable, _, eventTable, _ := WispTableRouting(isWisp)
var affectedIssues, affectedWisps []string
var aerr error
if isWisp {
affectedIssues, affectedWisps, aerr = AffectedByStatusChangeForWispInTx(ctx, tx, id)
} else {
affectedIssues, affectedWisps, aerr = AffectedByStatusChangeInTx(ctx, tx, id)
}
if aerr != nil {
return nil, fmt.Errorf("affected by close for %s: %w", id, aerr)View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped driver error after 'read status from <table>:' for the true cause
- Retry the close if transient (connection, lock timeout)
- Verify schema integrity and run migrations if the table exists but errors on read
- Adjust context timeouts; check for blocking transactions holding locks on the target table
Example fix
// before ctx := context.Background() closed, col, found, err := isClosedInTx(ctx, tx, id) // times out on huge table // after ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() closed, col, found, err := isClosedInTx(ctx, tx, id)
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify both probed tables are readable before close-policy checks
for _, t := range []string{"issues", "wisps"} {
var one int
err := db.QueryRow("SELECT 1 FROM " + t + " LIMIT 1").Scan(&one)
if err != nil && !dberrors.IsTableNotExist(err) {
return fmt.Errorf("%s unreadable before close: %w", t, err)
}
} Try / catch
err := CloseIssue(ctx, id, opts)
if err != nil && strings.Contains(err.Error(), "read status from") {
switch {
case dberrors.IsLockTimeout(err):
return retryCloseWithBackoff(ctx, id)
case dberrors.IsConnectionError(err) || errors.Is(err, context.DeadlineExceeded):
return retryClose(ctx, id)
default:
return fmt.Errorf("permanent failure closing %s: %w", id, err)
}
} Prevention
- Avoid running concurrent bulk updates against issues/wisps while closing issues
- Size context timeouts for your table sizes and network latency
- Run migrations atomically; a half-migrated wisps table will surface here
- Watch lock-wait metrics and tune innodb_lock_wait_timeout if timeouts recur
When it happens
Trigger: CloseIssue or EnforceClosePolicyInTx → isClosedInTx when 'SELECT status FROM <table> WHERE id = ?' fails: connection failure, lock wait timeout, permission denied, unreadable/corrupt table, or context cancellation — on either the issues or wisps table.
Common situations: Connection drop mid-close-policy check; lock contention from concurrent closes or bulk operations; partial wisp migration leaving wisps present but damaged; context timeout on a slow database.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- failed to begin transaction: %w
- failed to recompute is_blocked: %w
- failed to commit is_blocked repairs: %w
- %s: %w
- failed to query orphaned dependencies: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/847dfc9bc71882fb.
Report an issue: GitHub.