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
- Ensure batchHostVolumeUpdates is invoked only once per batchNodeUpdates instance, at client start (inside batchFirstFingerprints)
- Recreate the batchNodeUpdates object for each fingerprint round that needs batching instead of reusing it
- 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
- Treat batchNodeUpdates as strictly one-shot per client start
- Always create a fresh batchNodeUpdates on reconnect/restart paths
- Centralize the batchFirstFingerprints call in a single startup code path
- Assert single invocation in tests with a wrapper that panics on second call
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
- csi updates already batched
- driver updates already batched
- devices updates already batched
- missing accessor ID
- operation on unknown device(s) "%s/%s/%s" (%v): %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/47d6b6e5c5b669f3.
Report an issue: GitHub.