hashicorp/nomad · error
missing StagingTargetPath
Error message
missing StagingTargetPath
What it means
NodeStageVolumeRequest.Validate() rejects requests with an empty StagingTargetPath. Staging is the act of making a volume available at a well-known node-local path, so the plugin must know where to stage it. The library throws this before performing any storage operation.
Source
Thrown at plugins/csi/plugin.go:246
}
return &csipbv1.NodeStageVolumeRequest{
VolumeId: r.ExternalID,
PublishContext: r.PublishContext,
StagingTargetPath: r.StagingTargetPath,
VolumeCapability: r.VolumeCapability.ToCSIRepresentation(),
Secrets: r.Secrets,
VolumeContext: r.VolumeContext,
}
}
func (r *NodeStageVolumeRequest) Validate() error {
if r.ExternalID == "" {
return errors.New("missing volume ID")
}
if r.StagingTargetPath == "" {
return errors.New("missing StagingTargetPath")
}
if r.VolumeCapability == nil {
return errors.New("missing VolumeCapabilities")
}
return nil
}
type PluginCapabilitySet struct {
hasControllerService bool
hasTopologies bool
}
func (p *PluginCapabilitySet) HasControllerService() bool {
return p.hasControllerService
}
View on GitHub (pinned to 482b49bf1a)
Solutions
- Set StagingTargetPath to an absolute node-local path (e.g. /var/lib/kubelet/plugins/kubernetes.io/csi/pv/<id>/globalmount) before calling NodeStageVolume
- Ensure the caller generating the staging path (CO/node registrar) actually provides it
- Check for empty-string path produced by config substitution
Example fix
// before
req := &csi.NodeStageVolumeRequest{
ExternalID: volumeID,
VolumeCapability: cap,
}
// after
req := &csi.NodeStageVolumeRequest{
ExternalID: volumeID,
StagingTargetPath: "/var/nomad/staging/" + volumeID,
VolumeCapability: cap,
} Defensive patterns
Strategy: validation
Validate before calling
func validateStagingPath(req *csi.NodeStageVolumeRequest) error {
if req.StagingTargetPath == "" {
return errors.New("StagingTargetPath must be an absolute node-local path")
}
return nil
} Type guard
func hasStagingPath(req *csi.NodeStageVolumeRequest) bool {
return req != nil && req.StagingTargetPath != ""
} Try / catch
if err := req.Validate(); err != nil {
if strings.Contains(err.Error(), "missing StagingTargetPath") {
return fmt.Errorf("staging refused: derive StagingTargetPath from the volume ID before calling: %w", err)
}
return err
} Prevention
- Derive the staging path deterministically from the volume ID in one shared helper
- Keep the staging-path construction in a single package so it can't be omitted per-caller
- Add unit tests asserting the staging path is non-empty for every volume kind
When it happens
Trigger: Calling NodeStageVolume with StagingTargetPath left empty while ExternalID and VolumeCapability are set, e.g. a zero-value request or a caller that set only the volume ID.
Common situations: Custom CSI clients that forget the staging path; migrating code from non-staging CSI versions (older spec had no staging path); template/config rendering that dropped the path field.
Related errors
- missing NodeID
- missing ExternalID
- missing Name
- one of LimitBytes or RequiredBytes must be set if CapacityRa
- CSI.ControllerAttachVolume: VolumeID is required
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/bf8ae0b11e550946.
Report an issue: GitHub.