hashicorp/nomad · warning

host volume updates already batched

Error message

host volume updates already batched

What it means

batchHostVolumeUpdates registers a callback that flushes all batched host-volume node updates exactly once, guarded by hostVolumesBatched under a mutex. This error means the method was called a second time on the same batchNodeUpdates, which is a programming mistake: fingerprint batchers are one-shot per client startup.

Source

Thrown at client/node_updater.go:408

// this is the one that the volume manager runs
func (b *batchNodeUpdates) updateNodeFromHostVolume(name string, vol *structs.ClientHostVolumeConfig) {
	b.hostVolumeMu.Lock()
	defer b.hostVolumeMu.Unlock()
	if b.hostVolumesBatched {
		b.hostVolumeCB(name, vol) // => Client.updateNodeFromHostVol()
		return
	}
	hvm.UpdateVolumeMap(b.logger.Named("node_updater").With("method", "updateNodeFromHostVolume"),
		b.hostVolumes, name, vol)
}

// this one runs on client start
func (b *batchNodeUpdates) batchHostVolumeUpdates(f hvm.HostVolumeNodeUpdater) error {
	b.hostVolumeMu.Lock()
	defer b.hostVolumeMu.Unlock()
	if b.hostVolumesBatched {
		return fmt.Errorf("host volume updates already batched")
	}
	b.hostVolumesBatched = true
	for name, vol := range b.hostVolumes {
		f(name, vol) // => c.batchNodeUpdates.batchHostVolumeUpdates(FUNC
	}
	return nil
}

// updateNodeFromCSI implements csimanager.UpdateNodeCSIInfoFunc and is used in
// the csi manager to send csi fingerprints to the server.
func (b *batchNodeUpdates) updateNodeFromCSI(plugin string, info *structs.CSIInfo) {
	b.csiMu.Lock()
	defer b.csiMu.Unlock()
	if b.csiBatched {
		b.csiCB(plugin, info)
		return
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure batchHostVolumeUpdates is invoked only once per batchNodeUpdates instance, at client start (inside batchFirstFingerprints)
  2. Recreate the batchNodeUpdates object for each fingerprint round that needs batching instead of reusing it
  3. Guard call sites with a check of b.hostVolumesBatched, or log instead of returning an error if re-invocation is expected to be a no-op

Example fix

// before: reusing one batcher for repeated fingerprint rounds
b := newBatchNodeUpdates()
b.batchFirstFingerprints()
b.batchFirstFingerprints() // -> "host volume updates already batched"

// after: fresh batcher per round
b := newBatchNodeUpdates()
b.batchFirstFingerprints()

b = newBatchNodeUpdates()
b.batchFirstFingerprints()
Defensive patterns

Strategy: try-catch

Validate before calling

if b.hostVolumesBatched {
	// skip duplicate batch registration entirely
	return nil
}

Try / catch

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

Prevention

When it happens

Trigger: Calling batchNodeUpdates.batchHostVolumeUpdates more than once for the same client, e.g. invoking batchFirstFingerprints twice, or calling both batchFirstFingerprints and a manual batchHostVolumeUpdates on the same batcher instance.

Common situations: Refactoring client startup so first-fingerprint batching is triggered on reconnect in addition to initial start; accidental duplicate initialization of the node updater; test code reusing a batchNodeUpdates across runs without recreating it.

Related errors


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