hashicorp/nomad · error
snapshot cannot be nil
Error message
snapshot cannot be nil
What it means
CreateSnapshot returns this when an element of args.Snapshots is nil. The loop iterates over all requested snapshots and returns immediately (deliberately not appending to the multierror, per the inline comment, because the request state is 'weird') if any entry is nil. It is a caller-side payload validation failure of the CreateSnapshot RPC.
Source
Thrown at nomad/csi_endpoint.go:1614
aclObj, err := v.srv.ResolveACL(args)
if err != nil {
return err
}
if !allowVolume(aclObj, args.RequestNamespace()) || !aclObj.AllowPluginRead() {
return structs.ErrPermissionDenied
}
state, err := v.srv.fsm.State().Snapshot()
if err != nil {
return err
}
method := "ClientCSI.ControllerCreateSnapshot"
var mErr multierror.Error
for _, snap := range args.Snapshots {
if snap == nil {
// we intentionally don't multierror here because we're in a weird state
return fmt.Errorf("snapshot cannot be nil")
}
vol, err := state.CSIVolumeByID(nil, args.RequestNamespace(), snap.SourceVolumeID)
if err != nil {
multierror.Append(&mErr, fmt.Errorf("error querying volume %q: %v", snap.SourceVolumeID, err))
continue
}
if vol == nil {
multierror.Append(&mErr, fmt.Errorf("no such volume %q", snap.SourceVolumeID))
continue
}
pluginID := snap.PluginID
if pluginID == "" {
pluginID = vol.PluginID
}
plugin, err := state.CSIPluginByID(nil, pluginID)View on GitHub (pinned to 482b49bf1a)
Solutions
- Fix the caller to only populate non-nil snapshot entries before sending CSISnapshotCreateRequest
- Check the code that builds args.Snapshots for a mismatch between slice length and initialized elements (pre-sized slice with partial appends)
- Validate/de-duplicate the payload server-side-adjacent logic: filter nil entries before calling CreateSnapshot
- If the request came from JSON, fix the payload so no `null` elements appear in the Snapshots array
Example fix
// before
snaps := make([]*structs.CSISnapshot, 3)
snaps[0] = ...; snaps[1] = ... // snaps[2] stays nil
// after
snaps := []*structs.CSISnapshot{}
for _, s := range desired { if s != nil { snaps = append(snaps, s) } } Defensive patterns
Strategy: validation
Validate before calling
func sanitizeSnapshots(in []*structs.CSISnapshot) []*structs.CSISnapshot {
out := in[:0]
for _, s := range in { if s != nil && s.SourceVolumeID != "" { out = append(out, s) } }
return out
} Type guard
func validSnapshot(s *structs.CSISnapshot) bool { return s != nil && s.SourceVolumeID != "" } Try / catch
if err := createSnapshot(req); err != nil {
if strings.Contains(err.Error(), "snapshot cannot be nil") {
return fmt.Errorf("request contained nil snapshot entry; fix payload: %w", err)
}
return err
} Prevention
- Never build snapshot slices with make(len) + partial assignment; use append only
- Validate JSON payloads against a schema rejecting null array elements
- Unit-test batch request builders with edge cases that can emit nil entries
When it happens
Trigger: A caller (UI, API client, or job spec tooling) submits a CSISnapshotCreateRequest whose Snapshots slice contains a nil *CSISnapshot entry — e.g. constructing the slice with a fixed length and leaving one index unset, or unmarshalling JSON array entries of `null`.
Common situations: Batch snapshot scripts that append only some snapshots to a pre-sized slice (`make([]*structs.CSISnapshot, n)` and a partial loop); JSON payloads like `{"Snapshots":[null]}`; a deserialization bug or an upstream wrapper that passes nil through for skipped entries.
Related errors
- volume snapshot ID cannot be updated
- CSI.ControllerCreateSnapshot: %v
- controller create snapshot: %v
- controller delete snapshot: %v
- controller list snapshots: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/c69a00b04a5b8321.
Report an issue: GitHub.