vitessio/vitess · error

negative capacity

Error message

negative capacity

What it means

ConnPool.setCapacity panics when asked to shrink/expand the pool to a negative capacity. Capacity is an int64 atomic and a negative value has no meaning, so the internal setter fails fast instead of corrupting pool accounting (oldcap swap, drain logic).

Source

Thrown at go/pools/smartconnpool/pool.go:853

// If the capacity is smaller than the number of connections that there are
// currently open, we'll close enough connections before returning, even if
// that means waiting for clients to return connections to the pool.
// If the given context times out before we've managed to close enough connections
// an error will be returned.
func (pool *ConnPool[C]) SetCapacity(ctx context.Context, newcap int64) error {
	pool.capacityMu.Lock()
	defer pool.capacityMu.Unlock()
	if pool.close.Load() == nil {
		return ErrConnPoolClosed
	}
	return pool.setCapacity(ctx, newcap)
}

// setCapacity is the internal implementation for SetCapacity; it must be called
// with pool.capacityMu being held
func (pool *ConnPool[C]) setCapacity(ctx context.Context, newcap int64) error {
	if newcap < 0 {
		panic("negative capacity")
	}

	oldcap := pool.capacity.Swap(newcap)
	// Skip the drain only when capacity is unchanged AND we're already at or
	// below the target. Otherwise we may have been left with active > newcap
	// by a prior call that timed out (e.g. SetCapacity(0) racing with held
	// conns), and CloseWithContext relies on a follow-up call here to finish
	// draining.
	if oldcap == newcap && pool.active.Load() <= newcap {
		return nil
	}
	// update the idle count to match the new capacity if necessary
	// wait for connections to be returned to the pool if we're reducing the capacity.
	defer pool.setIdleCount()

	const delay = 10 * time.Millisecond

	// close connections until we're under capacity

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Validate the new capacity before calling SetCapacity: if newcap < 0, clamp to 0 or reject the change
  2. Fix the computation that produced the negative value (log/inspect oldcap and delta)
  3. Sanitize configuration at startup so negative pool sizes are rejected in PreRun/config validation

Example fix

// before
pool.SetCapacity(ctx, current-int64(released)) // may be negative
// after
newCap := current - int64(released)
if newCap < 0 {
    newCap = 0
}
pool.SetCapacity(ctx, newCap)
Defensive patterns

Strategy: validation

Validate before calling

if newCap < 0 {
    return fmt.Errorf("invalid capacity %d", newCap)
}
pool.SetCapacity(ctx, newCap)

Type guard

func validCapacity(n int64) bool { return n >= 0 }

Prevention

When it happens

Trigger: Calling pool.SetCapacity(ctx, n) (or resize paths) with a negative n, e.g. n computed as current - delta where delta exceeds current, or parsing a negative config value.

Common situations: Config with a negative capacity value; arithmetic like SetCapacity(cap-overflow) after accounting for connections about to be released; integer underflow in autoscaling code.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/be51d33461bbab88. Report an issue: GitHub.