{"record":{"id":"9c9c9afdb2e7b0cc","repo":"hashicorp/nomad","slug":"missing-snapshotid","errorCode":null,"errorMessage":"missing SnapshotID","messagePattern":"missing SnapshotID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/plugin.go","lineNumber":808,"sourceCode":"\tCreateTime     int64\n\tIsReady        bool\n}\n\ntype ControllerDeleteSnapshotRequest struct {\n\tSnapshotID string\n\tSecrets    structs.CSISecrets\n}\n\nfunc (r *ControllerDeleteSnapshotRequest) ToCSIRepresentation() *csipbv1.DeleteSnapshotRequest {\n\treturn &csipbv1.DeleteSnapshotRequest{\n\t\tSnapshotId: r.SnapshotID,\n\t\tSecrets:    r.Secrets,\n\t}\n}\n\nfunc (r *ControllerDeleteSnapshotRequest) Validate() error {\n\tif r.SnapshotID == \"\" {\n\t\treturn errors.New(\"missing SnapshotID\")\n\t}\n\treturn nil\n}\n\ntype ControllerListSnapshotsRequest struct {\n\tMaxEntries    int32\n\tStartingToken string\n\tSecrets       structs.CSISecrets\n}\n\nfunc (r *ControllerListSnapshotsRequest) ToCSIRepresentation() *csipbv1.ListSnapshotsRequest {\n\treturn &csipbv1.ListSnapshotsRequest{\n\t\tMaxEntries:    r.MaxEntries,\n\t\tStartingToken: r.StartingToken,\n\t\tSecrets:       r.Secrets,\n\t}\n}\n","sourceCodeStart":790,"sourceCodeEnd":826,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/plugin.go#L790-L826","documentation":"This error is returned by ControllerDeleteSnapshotRequest.Validate when SnapshotID is empty. Deleting a snapshot requires the provider-assigned snapshot ID to identify which snapshot to remove; an empty ID is treated as a malformed request and rejected locally before the ControllerDeleteSnapshot gRPC call.","triggerScenarios":"Calling the delete-snapshot path with ControllerDeleteSnapshotRequest{SnapshotID: \"\"} — e.g. cleanup automation operating on a snapshot record whose creation failed and thus never received an ID, or a zero-value request struct.","commonSituations":"Retention jobs iterating over snapshot lists where one entry has an empty ID (failed creation); deleting by snapshot name instead of ID and passing the empty lookup result; env-var interpolation leaving the ID blank.","solutions":["Populate SnapshotID with the provider-assigned ID from ControllerCreateSnapshotResponse before deleting.","Skip records with empty snapshot IDs in cleanup loops instead of passing them through.","Look up the snapshot ID via a list-snapshots call (e.g. by Name) if only the name is known.","Fix upstream creation failures that leave snapshot records without IDs."],"exampleFix":"// before\nfor _, s := range snaps {\n  client.DeleteSnapshot(&ControllerDeleteSnapshotRequest{SnapshotID: s.ID}) // may be \"\"\n}\n// after\nfor _, s := range snaps {\n  if s.ID == \"\" { continue }\n  client.DeleteSnapshot(&ControllerDeleteSnapshotRequest{SnapshotID: s.ID})\n}","handlingStrategy":"validation","validationCode":"if req.SnapshotID == \"\" {\n\treturn fmt.Errorf(\"cannot delete snapshot: snapshot ID is required\")\n}","typeGuard":"func deletableSnapshot(r *ControllerDeleteSnapshotRequest) bool {\n\treturn r != nil && r.SnapshotID != \"\"\n}","tryCatchPattern":null,"preventionTips":["Skip snapshot records with empty IDs in retention/cleanup loops.","Keep the ID returned by ControllerCreateSnapshotResponse alongside the name.","Resolve names to IDs via a list-snapshots call before deleting by name."],"tags":["csi","validation","missing-field","snapshot","storage"],"backgroundTag":"missing-required-argument","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}