hashicorp/nomad · warning

driver updates already batched

Error message

driver updates already batched

What it means

batchDriverUpdates registers the one-shot callback that flushes batched driver node updates, guarded by driversBatched under driversMu. This error indicates a second invocation on the same batchNodeUpdates, which by design supports only a single first-fingerprint driver update flush.

Source

Thrown at client/node_updater.go:476

// used in the driver manager to send driver fingerprints to
func (b *batchNodeUpdates) updateNodeFromDriver(driver string, info *structs.DriverInfo) {
	b.driversMu.Lock()
	defer b.driversMu.Unlock()
	if b.driversBatched {
		b.driverCB(driver, info)
		return
	}

	b.drivers[driver] = info
}

// batchDriverUpdates sends all of the batched driver node updates by calling f
// for each driver batched
func (b *batchNodeUpdates) batchDriverUpdates(f drivermanager.UpdateNodeDriverInfoFn) error {
	b.driversMu.Lock()
	defer b.driversMu.Unlock()
	if b.driversBatched {
		return fmt.Errorf("driver updates already batched")
	}

	b.driversBatched = true
	for driver, info := range b.drivers {
		f(driver, info)
	}
	return nil
}

// updateNodeFromDevices implements devicemanager.UpdateNodeDevicesFn and is
// used in the device manager to send device fingerprints to
func (b *batchNodeUpdates) updateNodeFromDevices(devices []*structs.NodeDeviceResource) {
	b.devicesMu.Lock()
	defer b.devicesMu.Unlock()
	if b.devicesBatched {
		b.devicesCB(devices)
		return
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Invoke batchDriverUpdates only once per batchNodeUpdates, during initial client startup
  2. Instantiate a new batchNodeUpdates for any additional fingerprint round
  3. Check call flow so reconnect/restart paths construct fresh batchers rather than reusing the startup one

Example fix

// before: retrying batched first fingerprints with same batcher
for round := 0; round < 2; round++ {
    b.batchDriverUpdates(fn) // fails on round 1
}

// after: one batcher per round
for round := 0; round < 2; round++ {
    b := newBatchNodeUpdates()
    b.batchDriverUpdates(fn)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if b.driversBatched {
	return nil // batch already registered
}

Try / catch

if err := b.batchDriverUpdates(fn); err != nil {
	if err.Error() == "driver updates already batched" {
		logger.Debug("driver batch already registered; ignoring")
		return nil
	}
	return err
}

Prevention

When it happens

Trigger: Calling batchNodeUpdates.batchDriverUpdates (directly or via batchFirstFingerprints) more than once on the same batcher instance.

Common situations: Client restart logic that re-triggers batchFirstFingerprints on the original batcher; accidental double registration of the driver manager fingerprinter; tests sharing a batchNodeUpdates across subtests.

Related errors


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