{"record":{"id":"bc093d4780ee9576","repo":"hashicorp/nomad","slug":"csi-controllerlistsnapshots-v","errorCode":null,"errorMessage":"CSI.ControllerListSnapshots: %v","messagePattern":"CSI\\.ControllerListSnapshots: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/csi_endpoint.go","lineNumber":471,"sourceCode":"\t\t// should retry with another controller instance\n\t\treturn fmt.Errorf(\"CSI.ControllerListSnapshots: %w: %v\",\n\t\t\tnstructs.ErrCSIClientRPCRetryable, err)\n\t}\n\tdefer plugin.Close()\n\n\tcsiReq := req.ToCSIRequest()\n\n\tctx, cancelFn := c.requestContext()\n\tdefer cancelFn()\n\n\t// CSI ControllerListSnapshots errors for timeout, codes.Unavailable and\n\t// codes.ResourceExhausted are retried; all other errors are fatal.\n\tcresp, err := plugin.ControllerListSnapshots(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.ControllerListSnapshots: %v\", err)\n\t}\n\n\tresp.NextToken = cresp.NextToken\n\tresp.Entries = []*nstructs.CSISnapshot{}\n\n\tfor _, entry := range cresp.Entries {\n\t\tif entry.Snapshot == nil {\n\t\t\treturn fmt.Errorf(\"CSI.ControllerListSnapshot: plugin returned an invalid entry\")\n\t\t}\n\t\tsnap := &nstructs.CSISnapshot{\n\t\t\tID:                     entry.Snapshot.ID,\n\t\t\tExternalSourceVolumeID: entry.Snapshot.SourceVolumeID,\n\t\t\tSizeBytes:              entry.Snapshot.SizeBytes,\n\t\t\tCreateTime:             entry.Snapshot.CreateTime,\n\t\t\tIsReady:                entry.Snapshot.IsReady,\n\t\t\tPluginID:               req.PluginID,\n\t\t}\n\t\tresp.Entries = append(resp.Entries, snap)","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/csi_endpoint.go#L453-L489","documentation":"This wraps the error from the plugin's ControllerListSnapshots gRPC call, which is executed with a per-attempt timeout (CSIPluginRequestTimeout) and up to 3 attempts with exponential backoff for retryable codes. Any error still returned after retries is surfaced here with the underlying gRPC/CSI status embedded.","triggerScenarios":"ListSnapshots against the plugin fails after internal retries: deadline exceeded, persistent Unavailable, ResourceExhausted (e.g. backend throttling list calls), or fatal CSI codes from the backend API.","commonSituations":"Cloud API rate limiting when listing many snapshots; slow storage backends exceeding the per-attempt timeout; plugin/backend connectivity issues; pagination requests against an unhealthy backend.","solutions":["Read the wrapped status code; for ResourceExhausted, reduce list frequency or page size (Secrets/MaxEntries, NextToken)","Retry the list later if the backend was throttling or briefly unavailable","Check controller plugin logs and backend health for outages","Use next_token pagination to make listing calls smaller and less likely to time out"],"exampleFix":"// before: one giant unpaginated list\nreq := &csi.ListSnapshotsRequest{}\n// after: paginate\nreq := &csi.ListSnapshotsRequest{MaxEntries: 100, StartingToken: nextToken}","handlingStrategy":"retry","validationCode":"// Reduce result size before listing to avoid backend throttling/timeout:\nreq := &structs.ClientCSIControllerListSnapshotsRequest{\n    PluginID: pluginID,\n    NextToken: nextToken, // paginate\n    MaxEntries: 100,\n}","typeGuard":null,"tryCatchPattern":"// Inspect wrapped status; retry only transient codes\nerr := c.ControllerListSnapshots(req, resp)\nif err != nil {\n    if st, ok := status.FromError(errors.Unwrap(err)); ok &&\n        (st.Code() == codes.Unavailable || st.Code() == codes.ResourceExhausted) {\n        // back off longer, then retry\n    }\n}","preventionTips":["Paginate list calls instead of fetching everything at once","Respect backend API rate limits when snapshot counts are large","Check backend health when list latency grows","Keep per-attempt plugin timeouts in mind when sizing pages"],"tags":["csi","grpc","snapshot","timeout","pagination"],"backgroundTag":"grpc-deadline-exceeded","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"}