{"record":{"id":"0a1f692b42780934","repo":"hashicorp/nomad","slug":"missing-targetpath","errorCode":null,"errorMessage":"missing TargetPath","messagePattern":"missing TargetPath","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/plugin.go","lineNumber":183,"sourceCode":"\treturn &csipbv1.NodePublishVolumeRequest{\n\t\tVolumeId:          r.ExternalID,\n\t\tPublishContext:    r.PublishContext,\n\t\tStagingTargetPath: r.StagingTargetPath,\n\t\tTargetPath:        r.TargetPath,\n\t\tVolumeCapability:  r.VolumeCapability.ToCSIRepresentation(),\n\t\tReadonly:          r.Readonly,\n\t\tSecrets:           r.Secrets,\n\t\tVolumeContext:     r.VolumeContext,\n\t}\n}\n\nfunc (r *NodePublishVolumeRequest) Validate() error {\n\tif r.ExternalID == \"\" {\n\t\treturn errors.New(\"missing volume ID\")\n\t}\n\n\tif r.TargetPath == \"\" {\n\t\treturn errors.New(\"missing TargetPath\")\n\t}\n\n\tif r.VolumeCapability == nil {\n\t\treturn errors.New(\"missing VolumeCapabilities\")\n\t}\n\n\treturn nil\n}\n\ntype NodeStageVolumeRequest struct {\n\t// The external ID of the volume to stage.\n\tExternalID string\n\n\t// If the volume was attached via a call to `ControllerPublishVolume` then\n\t// we need to provide the returned PublishContext here.\n\tPublishContext map[string]string\n\n\t// The path to which the volume MAY be staged. It MUST be an","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/plugin.go#L165-L201","documentation":"NodePublishVolumeRequest.Validate requires TargetPath, the filesystem path inside the allocation where the volume will be mounted. An empty TargetPath means the plugin has no destination to bind-mount the external volume to, so the request is rejected. This prevents publishing a volume without a mount point.","triggerScenarios":"A CSI NodePublishVolume call where r.TargetPath == \"\" — usually a job's volume_mount block missing the destination, or Nomad's mount point derivation failing so an empty path is passed to the plugin.","commonSituations":"Job spec `volume_mount { volume = \"...\" }` without a `destination`; template-generated jobs dropping the destination field; custom controllers building publish requests without the target path; CSI plugin version mismatch with an older Nomad client.","solutions":["Add `destination` to each volume_mount block in the job's task/group and resubmit: volume_mount { volume = \"data\", destination = \"/mnt/data\" }","Upgrade the Nomad client/plugins so mount paths are derived correctly","If constructing requests in Go, set TargetPath before calling Validate","Inspect `nomad job inspect` output to confirm the rendered volume_mount destinations are present"],"exampleFix":"// before (HCL)\nvolume_mount {\n  volume = \"data\"\n}\n\n// after (HCL)\nvolume_mount {\n  volume      = \"data\"\n  destination = \"/mnt/data\"\n}","handlingStrategy":"validation","validationCode":"if req.TargetPath == \"\" {\n    return fmt.Errorf(\"TargetPath is required\")\n}","typeGuard":null,"tryCatchPattern":"if err := req.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"missing TargetPath\") {\n        return fmt.Errorf(\"volume_mount destination missing in job spec: %w\", err)\n    }\n    return err\n}","preventionTips":["Set destination (absolute path) on every volume_mount block","Lint job specs for missing volume_mount destinations","Verify rendered jobs with `nomad job inspect` before submission","Keep Nomad client and CSI plugin versions compatible"],"tags":["csi","storage","mount","validation"],"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"}