{"record":{"id":"b41f07d218f33fef","repo":"hashicorp/nomad","slug":"must-specify-plugin-name-to-deregister","errorCode":null,"errorMessage":"must specify plugin name to deregister","messagePattern":"must specify plugin name to deregister","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/dynamicplugins/registry.go","lineNumber":252,"sourceCode":"\t\td.broadcasters[ptype] = broadcaster\n\t}\n\n\treturn broadcaster\n}\n\nfunc (d *dynamicRegistry) DeregisterPlugin(ptype, name, allocID string) error {\n\td.pluginsLock.Lock()\n\tdefer d.pluginsLock.Unlock()\n\n\tif ptype == \"\" {\n\t\t// This error shouldn't make it to a production cluster and is to aid\n\t\t// developers during the development of new plugin types.\n\t\treturn errors.New(\"must specify plugin type to deregister\")\n\t}\n\tif name == \"\" {\n\t\t// This error shouldn't make it to a production cluster and is to aid\n\t\t// developers during the development of new plugin types.\n\t\treturn errors.New(\"must specify plugin name to deregister\")\n\t}\n\tif allocID == \"\" {\n\t\treturn errors.New(\"must specify plugin allocation ID to deregister\")\n\t}\n\n\tpmap, ok := d.plugins[ptype]\n\tif !ok {\n\t\t// If this occurs there's a bug in the registration handler.\n\t\treturn fmt.Errorf(\"no plugins registered for type: %s\", ptype)\n\t}\n\n\tinfos, ok := pmap[name]\n\tif !ok {\n\t\t// plugin already deregistered, don't send events or try re-deleting.\n\t\treturn nil\n\t}\n\n\tvar info *PluginInfo","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/dynamicplugins/registry.go#L234-L270","documentation":"DeregisterPlugin needs the plugin name to find the specific registration within the type's plugin map. An empty name makes the deregistration ambiguous, so it is rejected with this developer-aid error.","triggerScenarios":"Calling Registry.DeregisterPlugin(ptype, \"\", allocID) with an empty name, e.g. when a CSI node plugin's deregistration handler passes an empty plugin name from a request or stale state.","commonSituations":"Alloc/deregistration event handlers building the name from a field that is unset, or cleanup code after an upgrade where the plugin name field changed.","solutions":["Pass the plugin name that was used at RegisterPlugin time","Validate the name is non-empty at the call site","Verify the deregistering handler reads the name from the correct field of the request/struct"],"exampleFix":"// before\nerr := registry.DeregisterPlugin(ptype, \"\", allocID)\n// after\nif name == \"\" {\n    return fmt.Errorf(\"cannot deregister plugin (type=%s): empty plugin name\", ptype)\n}\nerr := registry.DeregisterPlugin(ptype, name, allocID)","handlingStrategy":"validation","validationCode":"if name == \"\" {\n    return fmt.Errorf(\"deregister: plugin name is required\")\n}\nerr := registry.DeregisterPlugin(ptype, name, allocID)","typeGuard":"func canDeregister(ptype, name, allocID string) bool {\n    return ptype != \"\" && name != \"\" && allocID != \"\"\n}","tryCatchPattern":"err := registry.DeregisterPlugin(ptype, name, allocID)\nif err != nil {\n    if strings.Contains(err.Error(), \"must specify plugin name\") {\n        return fmt.Errorf(\"cannot deregister %s plugin: name missing: %w\", ptype, err)\n    }\n    return err\n}","preventionTips":["Keep the exact name used at RegisterPlugin alongside the plugin registration","Validate name fields on incoming deregistration requests","Guard against empty struct fields when copying plugin info between handlers"],"tags":["validation","plugin-registry","nomad"],"backgroundTag":"empty-required-field","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"}