gastownhall/beads · error
failed to batch-fetch child statuses from %s: %w
Error message
failed to batch-fetch child statuses from %s: %w
What it means
To decide closure eligibility, the function batch-fetches child issue statuses with `SELECT id, status FROM <table> WHERE id IN (...)`. A query failure on a table that exists (the not-exist case is tolerated for wisps) is wrapped with this message and the table name. It means child statuses could not be loaded, so epics cannot be safely evaluated for closure.
Source
Thrown at internal/storage/issueops/epic_closure.go:92
childStatusMap := make(map[string]string)
if len(allChildIDs) > 0 {
// Check both issues and wisps tables for child statuses (bd-w2w)
for _, table := range []string{"issues", "wisps"} {
for start := 0; start < len(allChildIDs); start += queryBatchSize {
end := start + queryBatchSize
if end > len(allChildIDs) {
end = len(allChildIDs)
}
batch := allChildIDs[start:end]
placeholders, args := buildSQLInClause(batch)
statusQuery := fmt.Sprintf("SELECT id, status FROM %s WHERE id IN (%s)", table, placeholders)
statusRows, err := tx.QueryContext(ctx, statusQuery, args...)
if err != nil {
if isTableNotExistError(err) {
break // wisps table may not exist on pre-migration databases
}
return nil, fmt.Errorf("failed to batch-fetch child statuses from %s: %w", table, err)
}
for statusRows.Next() {
var id, status string
if err := statusRows.Scan(&id, &status); err != nil {
statusRows.Close()
return nil, fmt.Errorf("scan child status: %w", err)
}
childStatusMap[id] = status
}
statusRows.Close()
}
}
}
// Step 4: Batch-fetch all epic issues
epicsWithChildren := make([]string, 0)
for _, epicID := range epicIDs {
if len(epicChildMap[epicID]) > 0 {View on GitHub (pinned to 71377f2769)
Solutions
- Read the table name and wrapped cause; verify the table has `id` and `status` columns.
- Retry — transient connection errors usually clear.
- If parameter limits are the cause, split work into smaller batches or chunk epics.
- Run migrations to fix schema drift.
Defensive patterns
Strategy: retry
Validate before calling
if len(childIDs) > 500 { return errors.New("child set too large; chunk before closure analysis") }
if err := db.PingContext(ctx); err != nil { return err } Type guard
func isStatusFetchErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to batch-fetch child statuses from")
} Try / catch
epics, err := GetEpicsEligibleForClosureInTx(ctx, tx)
if err != nil {
if isStatusFetchErr(err) && errors.Is(err, driver.ErrBadConn) {
return retry(ctx, epics)
}
return err
} Prevention
- Chunk very large child ID sets instead of one giant IN clause.
- Keep connection pools healthy for long batch operations.
- Run migrations so status columns match expectations.
- Schedule closure jobs during low write traffic.
When it happens
Trigger: Calling GetEpicsEligibleForClosureInTx when the batched status query errors — too many placeholders/args overflow on huge child sets, connection failure, or missing status column.
Common situations: Very large epics producing SQL statements that exceed driver parameter limits; Dolt server restarts mid-command; schema drift removing the status column.
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 get epics: %w
- failed to batch-fetch epic issues: %w
- get events: %w
- querying epics: %w
- querying blocked issues: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/0714938d14782dad.
Report an issue: GitHub.