{"record":{"id":"02e57c7d29c909a2","repo":"hashicorp/nomad","slug":"device-type-must-be-specified","errorCode":null,"errorMessage":"device type must be specified","messagePattern":"device type must be specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/device/device.go","lineNumber":95,"sourceCode":"\t// Name is the devices model name.\n\tName string\n\n\t// Devices is the set of device instances.\n\tDevices []*Device\n\n\t// Attributes are a set of attributes shared for all the devices.\n\tAttributes map[string]*structs.Attribute\n}\n\n// Validate validates that the device group is valid\nfunc (d *DeviceGroup) Validate() error {\n\tvar mErr multierror.Error\n\n\tif d.Vendor == \"\" {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"device vendor must be specified\"))\n\t}\n\tif d.Type == \"\" {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"device type must be specified\"))\n\t}\n\tif d.Name == \"\" {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"device name must be specified\"))\n\t}\n\n\tfor i, dev := range d.Devices {\n\t\tif dev == nil {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"device %d is nil\", i))\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := dev.Validate(); err != nil {\n\t\t\t_ = multierror.Append(&mErr, multierror.Prefix(err, fmt.Sprintf(\"device %d: \", i)))\n\t\t}\n\t}\n\n\tfor k, v := range d.Attributes {\n\t\tif err := v.Validate(); err != nil {","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/device/device.go#L77-L113","documentation":"Appended by DeviceGroup.Validate() when the device group's Type field is empty. Nomad requires a canonical device type (e.g. \"gpu\", plugins/device/device.go DeviceTypeGPU) so schedulers can match task device requests to fingerprinted groups.","triggerScenarios":"Fingerprinting returns a DeviceGroup with Type == \"\" and Validate() is called; or a plugin sets a type that is empty rather than a canonical DeviceType* constant.","commonSituations":"Custom device plugin not setting Type; plugin config missing the device-type option; refactored plugin code dropping the field.","solutions":["Set Type to a canonical constant such as device.DeviceTypeGPU (\"gpu\") in the plugin's DeviceGroup and restart","Fix the plugin's configuration so the device type is provided during fingerprinting","Call Validate() in the plugin before publishing groups to fail fast with the multierror details"],"exampleFix":"// before\nvar t string\n// after\nt := device.DeviceTypeGPU // \"gpu\"\ng := &device.DeviceGroup{Vendor: \"nvidia\", Type: t, Name: \"k80\"}","handlingStrategy":"validation","validationCode":"// Go: guard before returning a DeviceGroup\nif g.Type == \"\" {\n    return nil, fmt.Errorf(\"device group %s/%s missing type\", g.Vendor, g.Name)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use canonical constants (device.DeviceTypeGPU etc.) instead of ad-hoc strings for Type","Run Validate() on every DeviceGroup before emitting it from Fingerprint","Test fingerprint output against the canonical type set"],"tags":["devices","validation","plugin"],"backgroundTag":"missing-required-argument","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"}