hashicorp/nomad · error

no plugin for that allocation

Error message

no plugin for that allocation

What it means

PluginForAlloc found plugins registered under the type and name, but none of the registered instances has the requested AllocID. The registry keeps a list per plugin name (multiple allocations can host the same plugin name over time); the caller's allocID did not match any list entry. Distinguishes "plugin exists" from "this specific allocation's instance is gone".

Source

Thrown at client/dynamicplugins/registry.go:429

func (d *dynamicRegistry) PluginForAlloc(ptype, name, allocID string) (*PluginInfo, error) {
	d.pluginsLock.Lock()
	defer d.pluginsLock.Unlock()

	pmap, ok := d.plugins[ptype]
	if !ok {
		return nil, fmt.Errorf("no plugins registered for type: %s", ptype)
	}

	infos, ok := pmap[name]
	if ok {
		for e := infos.Front(); e != nil; e = e.Next() {
			plugin := e.Value.(*PluginInfo)
			if plugin.AllocID == allocID {
				return plugin, nil
			}
		}
	}
	return nil, fmt.Errorf("no plugin for that allocation")
}

// PluginsUpdatedCh returns a channel over which plugin events for the requested
// plugin type will be emitted. These events are strongly ordered and will never
// be dropped.
//
// The receiving channel _must not_ be closed before the provided context is
// cancelled.
func (d *dynamicRegistry) PluginsUpdatedCh(ctx context.Context, ptype string) <-chan *PluginUpdateEvent {
	b := d.broadcasterForPluginType(ptype)
	ch := b.subscribe()
	go func() {
		select {
		case <-b.shutdownCh:
			return
		case <-ctx.Done():
			b.unsubscribe(ch)
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Re-fetch the current allocation ID from the allocation/task state instead of a cached one.
  2. Confirm the plugin allocation is still running on this client (nomad alloc status <id>).
  3. If the alloc was rescheduled, look up the plugin by the new allocation ID or re-run the operation against the new instance.
  4. Add retry logic that re-reads the registry on this error since registration is dynamic.

Example fix

// before
info, err := registry.PluginForAlloc("csi-plugin", "aws-ebs", oldAllocID) // alloc rescheduled
// after
allocID := task.GetAlloc().ID // current allocation
info, err := registry.PluginForAlloc("csi-plugin", "aws-ebs", allocID)
Defensive patterns

Strategy: validation

Validate before calling

// always derive allocID from live state, never cache it across reschedules
allocID := taskEnv.AllocID // current allocation ID from the task environment/hook
if allocID == "" { return fmt.Errorf("cannot look up plugin: no allocation ID available") }

Try / catch

info, err := registry.PluginForAlloc(ptype, name, allocID)
if err != nil && strings.Contains(err.Error(), "no plugin for that allocation") {
    // stale allocID: re-read current state and retry once
    return fmt.Errorf("plugin %s/%s no longer served by alloc %s (rescheduled?): %w", name, ptype, allocID, err)
}

Prevention

When it happens

Trigger: Calling PluginForAlloc with an allocID that was never registered or has since been deregistered - e.g. the plugin allocation was restarted/rescheduled and a new allocID replaced the old one; passing a stale allocID captured earlier.

Common situations: A CSI plugin allocation rescheduled to another node or restarted with a new allocation ID while a volume/task still references the old ID; client GC removed the plugin registration; using an allocID from a stale plan or task state.

Related errors


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