{"record":{"id":"55a50f7de30c293e","repo":"hashicorp/nomad","slug":"plugin-group-already-shutdown","errorCode":null,"errorMessage":"plugin group already shutdown","messagePattern":"plugin group already shutdown","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/pluginmanager/group.go","lineNumber":43,"sourceCode":"\tmLock sync.Mutex\n\n\tlogger log.Logger\n}\n\n// New returns an initialized PluginGroup\nfunc New(logger log.Logger) *PluginGroup {\n\treturn &PluginGroup{\n\t\tmanagers: []PluginManager{},\n\t\tlogger:   logger.Named(\"plugin\"),\n\t}\n}\n\n// RegisterAndRun registers the manager and starts it in a separate goroutine\nfunc (m *PluginGroup) RegisterAndRun(manager PluginManager) error {\n\tm.mLock.Lock()\n\tdefer m.mLock.Unlock()\n\tif m.shutdown {\n\t\treturn fmt.Errorf(\"plugin group already shutdown\")\n\t}\n\tm.managers = append(m.managers, manager)\n\n\tm.logger.Info(\"starting plugin manager\", \"plugin-type\", manager.PluginType())\n\tmanager.Run()\n\treturn nil\n}\n\n// WaitForFirstFingerprint returns a channel which will be closed once all\n// plugin managers are ready. A timeout for waiting on each manager is given\nfunc (m *PluginGroup) WaitForFirstFingerprint(ctx context.Context) (<-chan struct{}, error) {\n\tm.mLock.Lock()\n\tdefer m.mLock.Unlock()\n\tif m.shutdown {\n\t\treturn nil, fmt.Errorf(\"plugin group already shutdown\")\n\t}\n\n\tvar wg sync.WaitGroup","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/pluginmanager/group.go#L25-L61","documentation":"PluginGroup.RegisterAndRun registers a plugin manager and starts it in a goroutine. If the group has already been shut down (shutdown flag set), registration is refused with this error to prevent adding managers to a stopped group.","triggerScenarios":"RegisterAndRun (or BuildPluginGroup usage) is invoked after PluginGroup.Shutdown() has completed — e.g. a late client init path or NewClient retry trying to register a CSI/driver manager onto a shutting-down group.","commonSituations":"Nomad client shutdown racing with agent reinitialization; custom code or tests constructing a client concurrently with shutdown; calling RegisterAndRun twice around a lifecycle where Shutdown already ran (e.g. reloading client config).","solutions":["Do not call RegisterAndRun after Shutdown; check the group lifecycle ordering in client setup code","Guard registration with the group's shutdown state or a lifecycle lock in custom integrations","If hit inside Nomad client startup after a shutdown, recreate the PluginGroup/client instead of reusing the old one","Retry client construction (NewClient) once the previous client has fully exited"],"exampleFix":"// before\nclient.shutdownCh <- struct{}{}\nclient.pluginManager.RegisterAndRun(driverMgr)  // panics-ish: returns already shutdown\n// after\nif !client.exited() {\n    if err := client.pluginManager.RegisterAndRun(driverMgr); err != nil {\n        logger.Error(\"plugin group unavailable\", \"err\", err)\n    }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := group.RegisterAndRun(manager); err != nil {\n    if err.Error() == \"plugin group already shutdown\" {\n        // recreate the PluginGroup/client instead of retrying registration\n        group = pluginmanager.NewPluginGroup(logger)\n        return group.RegisterAndRun(manager)\n    }\n    return err\n}","preventionTips":["Serialize client lifecycle: never register managers after calling Shutdown","Use a done/shutdown flag in custom integrations to gate RegisterAndRun calls","Rebuild PluginGroup objects on client reload instead of reusing shut-down ones","Add a mutex or single-flight wrapper around client construction and shutdown"],"tags":["nomad","plugin-manager","lifecycle","shutdown","race-condition"],"backgroundTag":"plugin-group-already-shutdown","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}