slackhq/nebula · error

ErrIndexAllocation

ErrIndexAllocation

Error message

failed to allocate local index

What it means

ErrIndexAllocation is returned by marshalOutgoing when the machine's index allocator (m.allocIndex) fails while trying to obtain a local index for the outgoing handshake message. The original allocator error is wrapped alongside it with fmt.Errorf("%w: %w", ...) so both causes are matchable with errors.Is. It signals the local node could not reserve a connection index, typically due to resource exhaustion.

Source

Thrown at handshake/errors.go:17

package handshake

import "errors"

var (
	ErrInitiateOnResponder     = errors.New("initiate called on responder")
	ErrInitiateAlreadyCalled   = errors.New("initiate already called")
	ErrInitiateNotCalled       = errors.New("initiate must be called before ProcessPacket for initiators")
	ErrPacketTooShort          = errors.New("packet too short")
	ErrPublicKeyMismatch       = errors.New("public key mismatch between certificate and handshake")
	ErrIncompleteHandshake     = errors.New("handshake completed without receiving required content")
	ErrMachineFailed           = errors.New("handshake machine has failed")
	ErrUnknownSubtype          = errors.New("unknown handshake subtype")
	ErrMissingContent          = errors.New("expected handshake content but message was empty")
	ErrUnexpectedContent       = errors.New("received unexpected handshake content")
	ErrInvalidRemoteIndex      = errors.New("peer sent an invalid index in handshake payload")
	ErrIndexAllocation         = errors.New("failed to allocate local index")
	ErrNoCredential            = errors.New("no handshake credential available for cert version")
	ErrAsymmetricCipherKeys    = errors.New("noise produced only one cipher key")
	ErrMultiMessageUnsupported = errors.New("multi-message handshake patterns are not yet supported by the manager")
	ErrSubtypeMismatch         = errors.New("packet subtype does not match handshake machine subtype")
)

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Release/free stale indexes when connections close so the allocator has capacity
  2. Inspect the wrapped cause with errors.Is/As to find the underlying allocator failure
  3. Increase the index pool size / max connection limit, or restart the node to reclaim leaked indexes
  4. Delay handshakes during shutdown when the allocator is closed

Example fix

// before: connections torn down without freeing indexes
conn.Close()

// after
idx := conn.Index()
conn.Close()
indexMgr.Free(idx) // return the index to the pool
Defensive patterns

Strategy: fallback

Validate before calling

if indexMgr.Remaining() == 0 {
    return errors.New("index pool exhausted; free indexes before handshaking")
}

Type guard

func allocatorHealthy(mgr *index.Manager) bool {
    return mgr != nil && !mgr.Closed() && mgr.Remaining() > 0
}

Try / catch

res, err := m.ProcessPacket(out, pkt)
var idxErr *fs.PathError
if errors.Is(err, handshake.ErrIndexAllocation) {
    // free stale indexes and retry after backoff
    indexMgr.FreeStale(idleTimeout)
    time.AfterFunc(backoff, func() { retryHandshake(conn) })
    return
}

Prevention

When it happens

Trigger: marshalOutgoing at handshake/machine.go:392 calls m.allocIndex() which returns an error (e.g. index table full or allocator closed), producing "failed to allocate local index: <cause>".

Common situations: Long-lived node exhausting its index space because old indexes are never released; allocator shut down during node shutdown while handshakes are still in flight; hitting a configured max-connections limit.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/b3947a73acf34ddc. Report an issue: GitHub.