hashicorp/nomad · warning

ErrAllocBroadcasterClosed

ErrAllocBroadcasterClosed

Error message

alloc broadcaster closed

What it means

ErrAllocBroadcasterClosed is returned by AllocBroadcaster.Send when the broadcaster has already been closed. The broadcaster distributes the latest alloc update to listeners (capacity-1 channels) without blocking; sending after Close is a programming/lifecycle error. Errors.Is/errors.As matching works via the sentinel value.

Source

Thrown at client/structs/broadcaster.go:21

package structs

import (
	"errors"
	"sync"

	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/nomad/nomad/structs"
)

const (
	// listenerCap is the capacity of the listener chans. Must be exactly 1
	// to prevent Sends from blocking and allows them to pop old pending
	// updates from the chan before enqueueing the latest update.
	listenerCap = 1
)

var ErrAllocBroadcasterClosed = errors.New("alloc broadcaster closed")

// AllocBroadcaster implements an allocation broadcast channel where each
// listener receives allocation updates. Pending updates are dropped and
// replaced by newer allocation updates, so listeners may not receive every
// allocation update. However this ensures Sends never block and listeners only
// receive the latest allocation update -- never a stale version.
type AllocBroadcaster struct {
	mu sync.Mutex

	// listeners is a map of unique ids to listener chans. lazily
	// initialized on first listen
	listeners map[int]chan *structs.Allocation

	// nextId is the next id to assign in listener map
	nextId int

	// closed is true if broadcaster is closed.
	closed bool

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Guard Send with the broadcaster's closed state or check ErrAllocBroadcasterClosed and treat it as benign shutdown noise
  2. Ensure no goroutines retain the broadcaster past its Close
  3. Use errors.Is(err, ErrAllocBroadcasterClosed) to filter it from real failures
  4. Restructure lifecycle so Senders are stopped before Close

Example fix

// before
b.Send(alloc) // panics-free but errors after Close
// after
if err := b.Send(alloc); err != nil && !errors.Is(err, structs.ErrAllocBroadcasterClosed) {
    return err
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := broadcaster.Send(alloc); err != nil {
    if errors.Is(err, structs.ErrAllocBroadcasterClosed) {
        return nil // benign: broadcaster shut down, drop the update
    }
    return err
}

Prevention

When it happens

Trigger: Calling b.Send(alloc) after b.Close() has been called — e.g. a late update arriving after the client shut down the allocation's broadcaster, as tested in broadcaster_test.go.

Common situations: Shutdown races where a hook or watcher still holds a reference and pushes an alloc update after Close; duplicate shutdown paths calling Close then Send.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/57aebef9d3e69919. Report an issue: GitHub.