gastownhall/beads · error
iter dependents: acquire conn: %w
Error message
iter dependents: acquire conn: %w
What it means
iterIssuesWithDepType acquires a dedicated connection from the pool (s.db.Conn) before streaming dependents rows, because the iterator owns the connection for its lifetime. This error wraps failure to obtain that connection: the pool is exhausted, the context was cancelled/timed out while waiting, or the DB handle is unhealthy. No query has run yet at this point.
Source
Thrown at internal/storage/dolt/iter_dependents.go:94
// GetDependenciesWithMetadata (which resolves targets across both `issues`
// and `wisps`) rather than a streaming join, because a dependency's target
// table cannot be determined from the edge table alone. There is no streaming
// caller for this direction today; revisit if one appears.
func (s *DoltStore) IterDependenciesWithMetadata(ctx context.Context, issueID string) (storage.Iter[types.IssueWithDependencyMetadata], error) {
deps, err := s.GetDependenciesWithMetadata(ctx, issueID)
if err != nil {
return nil, err
}
return storage.NewSliceIter(deps), nil
}
func (s *DoltStore) iterIssuesWithDepType(ctx context.Context, q string, args ...any) (storage.Iter[types.IssueWithDependencyMetadata], error) {
if s.closed.Load() {
return nil, ErrStoreClosed
}
conn, err := s.db.Conn(ctx)
if err != nil {
return nil, fmt.Errorf("iter dependents: acquire conn: %w", err)
}
rows, err := conn.QueryContext(ctx, q, args...)
if err != nil {
_ = conn.Close()
return nil, fmt.Errorf("iter dependents: query: %w", err)
}
return &doltDependentsIter{s: s, conn: conn, rows: rows}, nil
}
func (it *doltDependentsIter) Next(ctx context.Context) bool {
if it.err != nil || it.closed {
return false
}
if err := ctx.Err(); err != nil {
it.err = err
return false
}
if !it.rows.Next() {View on GitHub (pinned to 71377f2769)
Solutions
- Ensure every returned iterator is fully drained or closed — leaked doltDependentsIter connections exhaust the pool (this is the most common root cause).
- Increase the SQL pool size (SetMaxOpenConns) if workloads legitimately need many concurrent iterators.
- Check the wrapped cause: context deadline exceeded means contention; raise the timeout or reduce concurrency.
- Restart the Dolt backend / reopen the store if the pool handle itself is unhealthy.
Example fix
// before
it, err := store.IterDependentsWithMetadata(ctx, issueID)
if err != nil { return err }
for it.Next(ctx) { ... } // iterator never closed -> conn leak
// after
it, err := store.IterDependentsWithMetadata(ctx, issueID)
if err != nil { return err }
defer it.Close() // releases the pooled conn
for it.Next(ctx) { ... } Defensive patterns
Strategy: try-catch
Validate before calling
// avoid opening new iterators while many are unclosed cctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() _ = cctx // pass cctx to IterDependentsWithMetadata to bound pool wait time
Type guard
func isConnAcquireErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "acquire conn")
} Try / catch
it, err := store.IterDependentsWithMetadata(ctx, issueID)
if err != nil {
if isConnAcquireErr(err) {
// pool exhausted or timeout: close leaked iterators, then retry
return fmt.Errorf("could not acquire DB connection (check for unclosed iterators): %w", err)
}
return err
}
defer it.Close() Prevention
- Always defer Close() (or drain) every iterator returned by IterDependentsWithMetadata
- Use context timeouts so pool waits fail fast instead of hanging
- Increase MaxOpenConns if you legitimately iterate many dependency graphs concurrently
- Monitor for 'acquire conn' failures as an early sign of connection leaks
When it happens
Trigger: Calling IterDependentsWithMetadata (which routes to iterIssuesWithDepType) when db.Conn(ctx) fails: all pool connections busy for longer than the context deadline, ctx cancelled by the caller, or the store's underlying Dolt handle is broken. Note ErrStoreClosed is returned separately before this.
Common situations: Long-running dependent iteration holding many connections in a loop that opens iterators without closing them; many concurrent bd commands against a small connection pool; slow/hung Dolt server making Conn block until the deadline.
Related errors
- checkout active branch %q: %w
- failed to rebuild pool after migration: %w
- acquire connection for gc: %w
- acquire connection for remote-ref prune: %w
- acquire connection for flatten: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4b84b7d7ce698d35.
Report an issue: GitHub.