gastownhall/beads · error
db: ChildCounterSQLRepository.NextChildID: probe parent tabl
Error message
db: ChildCounterSQLRepository.NextChildID: probe parent table for %s: %w
What it means
Wrapping error from ChildCounterSQLRepository.NextChildID at internal/storage/domain/db/child_counter.go:33. Before reading the counter, NextChildID probes which table the parent lives in (issues vs wisps) via r.parentIsActiveWisp; if that probe query fails, the child-ID generation aborts with this error. The %w chain preserves the SQL-level cause; parentID is interpolated into the message.
Source
Thrown at internal/storage/domain/db/child_counter.go:33
func NewChildCounterSQLRepository(runner Runner) domain.ChildCounterSQLRepository {
return &childCounterSQLRepositoryImpl{runner: runner}
}
type childCounterSQLRepositoryImpl struct {
runner Runner
}
var _ domain.ChildCounterSQLRepository = (*childCounterSQLRepositoryImpl)(nil)
func (r *childCounterSQLRepositoryImpl) NextChildID(ctx context.Context, parentID string, _ domain.ChildCounterOpts) (string, error) {
if parentID == "" {
return "", errors.New("db: ChildCounterSQLRepository.NextChildID: parentID must not be empty")
}
counterTable, issueTable := "child_counters", "issues"
parentIsWisp, err := r.parentIsActiveWisp(ctx, parentID)
if err != nil {
return "", fmt.Errorf("db: ChildCounterSQLRepository.NextChildID: probe parent table for %s: %w", parentID, err)
}
if parentIsWisp {
counterTable, issueTable = "wisp_child_counters", "wisps"
}
var lastChild int
err = r.runner.QueryRowContext(ctx,
//nolint:gosec // G201: counterTable is one of two hardcoded constants
fmt.Sprintf("SELECT last_child FROM %s WHERE parent_id = ?", counterTable),
parentID,
).Scan(&lastChild)
switch {
case err == nil:
case errors.Is(err, sql.ErrNoRows):
lastChild = 0
default:
return "", fmt.Errorf("db: ChildCounterSQLRepository.NextChildID: read counter for %s: %w", parentID, err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Unwrap the chain to see the SQL error from the parent-table probe
- Verify the parent ID exists and the issues/wisps tables are readable
- Reconnect to the database and retry
- If bulk-generating children, batch with retries around transient connection errors
Example fix
// before
parentIsWisp, err := r.parentIsActiveWisp(ctx, parentID)
if err != nil {
return "", fmt.Errorf("db: ChildCounterSQLRepository.NextChildID: probe parent table for %s: %w", parentID, err)
}
// after
parentIsWisp, err := r.parentIsActiveWisp(ctx, parentID)
if err != nil {
return "", fmt.Errorf("db: ChildCounterSQLRepository.NextChildID: probe parent table for %s: %w", parentID, err) // caller retries on transient errors
} Defensive patterns
Strategy: retry
Validate before calling
// validate inputs and storage before generating child IDs
if parentID == "" {
return errors.New("parentID must not be empty")
}
if err := pingStore(ctx); err != nil {
return fmt.Errorf("cannot generate child id, storage unreachable: %w", err)
} Try / catch
id, err := repo.NextChildID(ctx, parentID)
if err != nil && strings.Contains(err.Error(), "probe parent table") {
if isTransient(errors.Unwrap(err)) { // connection refused, deadline, lock timeout
backoff := 100 * time.Millisecond
for i := 0; i < 3; i++ {
time.Sleep(backoff)
backoff *= 2
if id, err = repo.NextChildID(ctx, parentID); err == nil {
break
}
}
}
}
return id, err Prevention
- Always check the parent ID exists before generating children
- Retry transient SQL errors with exponential backoff
- Keep connection pools healthy (set max open/idle limits)
- Run storage integrity checks if probe errors recur
When it happens
Trigger: Calling NextChildID(ctx, parentID) with a non-empty parentID whose table probe (parentIsActiveWisp) returns a DB error — SQL failure, connection loss, cancelled context. (An empty parentID produces a different, non-wrapped error on the preceding line.)
Common situations: Parent issue ID referencing a row in a corrupted DB; connection pool exhausted; Dolt server restarted mid-command while generating child IDs in bulk.
Related errors
- db: ChildCounterSQLRepository.NextChildID: read counter for
- db: ChildCounterSQLRepository.NextChildID: scan existing chi
- db: LabelSQLRepository.Insert %s/%s: %w
- failed to close issue: %w
- delete issue from %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9290b7b9d73cded4.
Report an issue: GitHub.