gastownhall/beads · error
count open durable children for %s: %w
Error message
count open durable children for %s: %w
What it means
Beads throws this when the durable-side COUNT query — counting open parent-child dependencies via dependencies JOIN issues — fails at the SQL layer. The raw driver error is wrapped with the parent issue id so you can see which record the count was for. It aborts the close-policy check, so the close operation does not proceed.
Source
Thrown at internal/storage/issueops/close.go:208
return countOpenChildrenForTargetInTx(ctx, tx, id, targetColumn)
}
func countOpenChildrenForTargetInTx(ctx context.Context, tx DBTX, id, targetColumn string) (int, error) {
if targetColumn != "depends_on_issue_id" && targetColumn != "depends_on_wisp_id" {
return 0, fmt.Errorf("count open children: unsupported target column %q", targetColumn)
}
var durableCount int
//nolint:gosec // G201: targetColumn is validated above against two hardcoded identifiers.
durableQuery := fmt.Sprintf(`
SELECT COUNT(DISTINCT dependency.issue_id)
FROM dependencies AS dependency
JOIN issues AS child ON child.id = dependency.issue_id
WHERE dependency.%s = ?
AND dependency.type = 'parent-child'
AND child.status != 'closed'
`, targetColumn)
if err := tx.QueryRowContext(ctx, durableQuery, id).Scan(&durableCount); err != nil {
return 0, fmt.Errorf("count open durable children for %s: %w", id, err)
}
var wispCount int
//nolint:gosec // G201: targetColumn is validated above against two hardcoded identifiers.
wispQuery := fmt.Sprintf(`
SELECT COUNT(DISTINCT dependency.issue_id)
FROM wisp_dependencies AS dependency
JOIN wisps AS child ON child.id = dependency.issue_id
WHERE dependency.%s = ?
AND dependency.type = 'parent-child'
AND child.status != 'closed'
AND NOT EXISTS (
SELECT 1 FROM dependencies AS durable WHERE durable.id = dependency.id
)
`, targetColumn)
if err := tx.QueryRowContext(ctx, wispQuery, id).Scan(&wispCount); err != nil {
if optionalBlockedTable("wisp_dependencies") && isTableNotExistError(err) {
return durableCount, nilView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped driver error (%w) for the root cause — it is appended after this message
- Retry the close if the cause was transient (connection blip, lock timeout); beads close is transactional and safe to retry
- Verify schema integrity (bd doctor / migrations applied) if the error is 'table doesn't exist' for dependencies or issues
- Check context deadlines if the error is context deadline exceeded — the dependency graph may be large or the DB slow
Example fix
// before ctx := context.Background() // no deadline, hangs then aborts on server timeout count, err := countOpenChildrenForTargetInTx(ctx, tx, id, col) // after ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() count, err := countOpenChildrenForTargetInTx(ctx, tx, id, col)
Defensive patterns
Strategy: retry
Validate before calling
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("database unreachable before close: %w", err)
} Try / catch
count, err := countOpenChildrenForTargetInTx(ctx, tx, id, col)
if err != nil {
var retryable bool
if errors.Is(err, context.DeadlineExceeded) || dberrors.IsLockTimeout(err) || dberrors.IsConnectionError(err) {
retryable = true
}
log.Printf("child count failed for %s (retryable=%v): %v", id, retryable, err)
if retryable {
return retryClose(ctx, id)
}
return err
} Prevention
- Set explicit context timeouts sized for your dependency-graph size
- Retry close operations on transient errors — they are transactional and idempotent
- Keep the driver and Dolt/MySQL server versions current and migrations applied
- Monitor connection pool health and lock-wait metrics in production
- Avoid concurrent bulk dependency writes while closing issues
When it happens
Trigger: Calling CloseIssue (or EnforceClosePolicyInTx / CloseIssueCheckedInTx) when the query 'SELECT COUNT(DISTINCT dependency.issue_id) FROM dependencies JOIN issues ... WHERE dependency.<col> = ?' returns a driver error: connection failure, lock wait timeout, corrupt schema, missing dependencies/issues table, or context cancellation/deadline exceeded mid-query.
Common situations: Database server restarted or network dropped mid-transaction; Dolt/MySQL error 1146 because the dependencies table is missing in a partially-migrated database; lock contention from another process holding rows in dependencies; context timeout on a slow, large dependency graph.
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/f8496cb8c586649f.
Report an issue: GitHub.