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

  1. Ensure every returned iterator is fully drained or closed — leaked doltDependentsIter connections exhaust the pool (this is the most common root cause).
  2. Increase the SQL pool size (SetMaxOpenConns) if workloads legitimately need many concurrent iterators.
  3. Check the wrapped cause: context deadline exceeded means contention; raise the timeout or reduce concurrency.
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/4b84b7d7ce698d35. Report an issue: GitHub.