hashicorp/nomad · error
CSI.ControllerListSnapshot: plugin returned an invalid entry
Error message
CSI.ControllerListSnapshot: plugin returned an invalid entry
What it means
In ControllerListSnapshots, after a successful plugin call each entry in cresp.Entries must contain a non-nil Snapshot. If an entry has a nil Snapshot, Nomad returns this error instead of dereferencing nil. Note the message says 'ListSnapshot' (singular) — a known typo — but it originates from the list-snapshots path. It indicates the CSI plugin returned a malformed response.
Source
Thrown at client/csi_endpoint.go:479
ctx, cancelFn := c.requestContext()
defer cancelFn()
// CSI ControllerListSnapshots errors for timeout, codes.Unavailable and
// codes.ResourceExhausted are retried; all other errors are fatal.
cresp, err := plugin.ControllerListSnapshots(ctx, csiReq,
grpc_retry.WithPerRetryTimeout(CSIPluginRequestTimeout),
grpc_retry.WithMax(3),
grpc_retry.WithBackoff(grpc_retry.BackoffExponential(100*time.Millisecond)))
if err != nil {
return fmt.Errorf("CSI.ControllerListSnapshots: %v", err)
}
resp.NextToken = cresp.NextToken
resp.Entries = []*nstructs.CSISnapshot{}
for _, entry := range cresp.Entries {
if entry.Snapshot == nil {
return fmt.Errorf("CSI.ControllerListSnapshot: plugin returned an invalid entry")
}
snap := &nstructs.CSISnapshot{
ID: entry.Snapshot.ID,
ExternalSourceVolumeID: entry.Snapshot.SourceVolumeID,
SizeBytes: entry.Snapshot.SizeBytes,
CreateTime: entry.Snapshot.CreateTime,
IsReady: entry.Snapshot.IsReady,
PluginID: req.PluginID,
}
resp.Entries = append(resp.Entries, snap)
if req.MaxEntries != 0 && int32(len(resp.Entries)) == req.MaxEntries {
break
}
}
return nil
}
View on GitHub (pinned to 482b49bf1a)
Solutions
- Report the malformed list response to the plugin author
- Upgrade the CSI plugin to a release fixing list response construction
- Validate the plugin directly with `csc controller list-snapshots` to reproduce and confirm
- Work around by filtering list queries (volume ID / snapshot ID / next_token) to skip malformed entries
Example fix
// before (plugin side)
for _, s := range snaps {
out.Entries = append(out.Entries, &csi.ListSnapshotsResponse_Entry{}) // snapshot forgotten
}
// after
for _, s := range snaps {
out.Entries = append(out.Entries, &csi.ListSnapshotsResponse_Entry{Snapshot: toProto(s)})
} Defensive patterns
Strategy: validation
Validate before calling
// Sanity-check list results at the plugin boundary before automation consumes them:
for _, e := range cresp.Entries {
if e.Snapshot == nil {
return fmt.Errorf("plugin %s returned a list entry without a snapshot", pluginName)
}
} Type guard
func hasSnapshot(e *csi.ListSnapshotsResponse_Entry) bool {
return e != nil && e.Snapshot != nil
} Try / catch
// Note the singular 'ListSnapshot' typo in the message when matching
if err := c.ControllerListSnapshots(req, resp); err != nil {
if strings.Contains(err.Error(), "plugin returned an invalid entry") {
// treat as plugin bug: upgrade or report to vendor
}
} Prevention
- Test plugin list-snapshots output with csc before production
- Pin plugin versions known to emit well-formed list entries
- Filter listings by volume/snapshot ID to limit malformed responses
- Report nil-entry responses to the plugin vendor promptly
When it happens
Trigger: The plugin's ListSnapshots response contains an Entries element with a nil Snapshot field while gRPC status was OK.
Common situations: Buggy plugin versions emitting partially-populated entries (e.g. deleted snapshots represented as empty entries); plugin/vendor SDK changes altering list response serialization; plugins built against mismatched CSI spec versions.
Related errors
- CSI.ControllerCreateSnapshot: plugin did not return error or
- CSI.ControllerListVolumes: plugin returned an invalid entry
- CSI.ControllerCreateSnapshot: %w: %v
- CSI.ControllerDeleteSnapshot: %w: %v
- CSI.ControllerDeleteSnapshot: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/33eb5c0a6ef93f9f.
Report an issue: GitHub.