{"record":{"id":"01f58c6954f05601","repo":"hashicorp/nomad","slug":"one-of-snapshotid-or-cloneid-must-be-set-if-conten","errorCode":null,"errorMessage":"one of SnapshotID or CloneID must be set if ContentSource is set","messagePattern":"one of SnapshotID or CloneID must be set if ContentSource is set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/plugin.go","lineNumber":511,"sourceCode":"\tif r.Name == \"\" {\n\t\treturn errors.New(\"missing Name\")\n\t}\n\tif r.VolumeCapabilities == nil {\n\t\treturn errors.New(\"missing VolumeCapabilities\")\n\t}\n\tif r.CapacityRange != nil {\n\t\tif r.CapacityRange.LimitBytes == 0 && r.CapacityRange.RequiredBytes == 0 {\n\t\t\treturn errors.New(\n\t\t\t\t\"one of LimitBytes or RequiredBytes must be set if CapacityRange is set\")\n\t\t}\n\t\tif r.CapacityRange.LimitBytes > 0 &&\n\t\t\tr.CapacityRange.LimitBytes < r.CapacityRange.RequiredBytes {\n\t\t\treturn errors.New(\"LimitBytes cannot be less than RequiredBytes\")\n\t\t}\n\t}\n\tif r.ContentSource != nil {\n\t\tif r.ContentSource.CloneID != \"\" && r.ContentSource.SnapshotID != \"\" {\n\t\t\treturn errors.New(\n\t\t\t\t\"one of SnapshotID or CloneID must be set if ContentSource is set\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// VolumeContentSource is snapshot or volume that the plugin will use to\n// create the new volume. At most one of these fields can be set, but nil (and\n// not an empty struct) is expected by CSI plugins if neither field is set.\ntype VolumeContentSource struct {\n\tSnapshotID string\n\tCloneID    string\n}\n\nfunc (vcr *VolumeContentSource) ToCSIRepresentation() *csipbv1.VolumeContentSource {\n\tif vcr == nil {\n\t\treturn nil\n\t}","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/plugin.go#L493-L529","documentation":"This error is returned by VolumeOptions.Validate when the ContentSource field is non-nil but contains both a CloneID and a SnapshotID. The CSI spec allows a volume to be provisioned from exactly one source, so the request is ambiguous and is rejected before any gRPC call to the storage provider is made.","triggerScenarios":"Calling NodePublishVolume (through the Validate path invoked from volume registration/job submission) with ContentSource = {CloneID: \"clone-1\", SnapshotID: \"snap-1\"}. The error only fires when both IDs are non-empty; setting neither yields no error for ContentSource.","commonSituations":"Merging two volume specs (one clone-based, one snapshot-based) with a YAML/JSON merge tool that keeps both keys; programmatically populating ContentSource from two config fields without mutually-exclusive enforcement; copy-paste between a clone example and a restore-from-snapshot example.","solutions":["Remove either CloneID or SnapshotID from ContentSource so exactly one source is set.","If the volume should be restored from a snapshot, clear CloneID and keep SnapshotID (and vice versa).","If content source is not intended at all, remove the ContentSource block entirely.","Fix the template/config generator to emit only one of the two fields."],"exampleFix":"// before\nContentSource: &CSIContentSource{\n  CloneID:    \"my-clone\",\n  SnapshotID: \"my-snapshot\",\n}\n// after\nContentSource: &CSIContentSource{\n  SnapshotID: \"my-snapshot\",\n}","handlingStrategy":"validation","validationCode":"func validateContentSource(cs *CSIContentSource) error {\n\tif cs != nil && cs.CloneID != \"\" && cs.SnapshotID != \"\" {\n\t\treturn fmt.Errorf(\"set only one of CloneID or SnapshotID\")\n\t}\n\treturn nil\n}","typeGuard":"func validContentSource(cs *CSIContentSource) bool {\n\treturn cs == nil || cs.CloneID == \"\" || cs.SnapshotID == \"\"\n}","tryCatchPattern":null,"preventionTips":["Model the source as a single tagged-union field (e.g. oneof snapshot|clone) in tooling.","Beware YAML/JSON merge tools that silently keep both keys.","Assert exactly-one-set in template rendering for restore specs."],"tags":["csi","validation","content-source","storage"],"backgroundTag":"mutually-exclusive-parameters","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"}