{"record":{"id":"9d2faba6180bf9bb","repo":"hashicorp/nomad","slug":"csi-controllerlistvolumes-plugin-returned-an-inva","errorCode":null,"errorMessage":"CSI.ControllerListVolumes: plugin returned an invalid entry","messagePattern":"CSI\\.ControllerListVolumes: plugin returned an invalid entry","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/csi_endpoint.go","lineNumber":344,"sourceCode":"\tctx, cancelFn := c.requestContext()\n\tdefer cancelFn()\n\n\t// CSI ControllerListVolumes errors for timeout, codes.Unavailable and\n\t// codes.ResourceExhausted are retried; all other errors are fatal.\n\tcresp, err := plugin.ControllerListVolumes(ctx, csiReq,\n\t\tgrpc_retry.WithPerRetryTimeout(CSIPluginRequestTimeout),\n\t\tgrpc_retry.WithMax(3),\n\t\tgrpc_retry.WithBackoff(grpc_retry.BackoffExponential(100*time.Millisecond)))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"CSI.ControllerListVolumes: %v\", err)\n\t}\n\n\tresp.NextToken = cresp.NextToken\n\tresp.Entries = []*nstructs.CSIVolumeExternalStub{}\n\n\tfor _, entry := range cresp.Entries {\n\t\tif entry.Volume == nil {\n\t\t\treturn fmt.Errorf(\"CSI.ControllerListVolumes: plugin returned an invalid entry\")\n\t\t}\n\t\tvol := &nstructs.CSIVolumeExternalStub{\n\t\t\tExternalID:    entry.Volume.ExternalVolumeID,\n\t\t\tCapacityBytes: entry.Volume.CapacityBytes,\n\t\t\tVolumeContext: entry.Volume.VolumeContext,\n\t\t\tCloneID:       entry.Volume.ContentSource.CloneID,\n\t\t\tSnapshotID:    entry.Volume.ContentSource.SnapshotID,\n\t\t}\n\t\tif entry.Status != nil {\n\t\t\tvol.PublishedExternalNodeIDs = entry.Status.PublishedNodeIds\n\t\t\tvol.IsAbnormal = entry.Status.VolumeCondition.Abnormal\n\t\t\tif entry.Status.VolumeCondition != nil {\n\t\t\t\tvol.Status = entry.Status.VolumeCondition.Message\n\t\t\t}\n\t\t}\n\t\tresp.Entries = append(resp.Entries, vol)\n\t\tif req.MaxEntries != 0 && int32(len(resp.Entries)) == req.MaxEntries {\n\t\t\tbreak","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/csi_endpoint.go#L326-L362","documentation":"CSI.ControllerListVolumes wraps the server RPC ControllerListVolumes. After the plugin responds, every entry in cresp.Entries is expected to carry a non-nil Volume. If a plugin returns an entry with a nil Volume (a malformed ListVolumesResponse), Nomad rejects the whole response instead of producing a stub with empty fields, so the caller gets this 'plugin returned an invalid entry' error. It signals a bug or non-conformance in the CSI plugin, not in Nomad's configuration.","triggerScenarios":"A CSI controller plugin's ListVolumes RPC returns a response whose Entries slice contains an element with a nil Volume field; the server RPC reached this client and iterated over that entry.","commonSituations":"Buggy or pre-spec CSI plugin builds that emit placeholder/partial list entries; plugins that paginate by appending empty marker entries; a plugin upgraded to a version that changed its list response shape; vendor SDKs that allow nil volumes in list results.","solutions":["Report the bug to the CSI plugin vendor/author; the plugin must never emit entries with nil Volume","Upgrade the CSI plugin to the latest version where list-response handling may be fixed","Deduce the offending plugin from the volume context and test its ListVolumes directly with csc controller list-volumes","As a workaround, narrow the listing (pagination/next_token or volume ID filters) to avoid the malformed entries"],"exampleFix":"// before (plugin side, pseudo-Go)\nentries = append(entries, &csi.ListVolumesResponse_Entry{})\n// after\nentries = append(entries, &csi.ListVolumesResponse_Entry{\n    Volume: &csi.Volume{VolumeId: id, CapacityBytes: cap},\n})","handlingStrategy":"validation","validationCode":"// Before relying on list output, sanity-check via the plugin directly:\n// nomad volume status  (external listing) and ensure the plugin version is current.\n// There is no caller-side pre-check inside Nomad; treat nil entries as plugin bugs.\nif entry.Volume == nil { /* plugin bug: report, upgrade plugin */ }","typeGuard":"func isValidVolumeEntry(e *csi.ListVolumesResponse_Entry) bool {\n    return e != nil && e.Volume != nil\n}","tryCatchPattern":"// Go: check the returned error from ControllerListVolumes\nif err := c.ControllerListVolumes(req, resp); err != nil {\n    if strings.Contains(err.Error(), \"plugin returned an invalid entry\") {\n        // fall back to another plugin version / report to vendor\n    }\n}","preventionTips":["Pin and keep the CSI plugin updated to a spec-conformant release","Test plugin ListVolumes with csc before production use","Avoid beta/unreleased plugin builds","Monitor for this error to catch plugin regressions after upgrades"],"tags":["csi","grpc","plugin","storage"],"backgroundTag":"csi-plugin-invalid-response","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"}