{"record":{"id":"cfe1e09c4bc8a803","repo":"hashicorp/nomad","slug":"alloc-q-failed-to-claim-volume-q-w","errorCode":null,"errorMessage":"alloc %q failed to claim volume %q: %w","messagePattern":"alloc %q failed to claim volume %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/state/state_store.go","lineNumber":2914,"sourceCode":"\t\t}\n\t}\n\n\tvolume, err := s.csiVolumeDenormalizePluginsTxn(txn, orig.Copy())\n\tif err != nil {\n\t\treturn err\n\t}\n\tvolume, err = s.csiVolumeDenormalizeTxn(txn, nil, volume)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// In the case of a job deregistration, there will be no allocation ID\n\t// for the claim but we still want to write an updated index to the volume\n\t// so that volume reaping is triggered\n\tif claim.AllocationID != \"\" {\n\t\terr = volume.Claim(claim, alloc)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"alloc %q failed to claim volume %q: %w\", claim.AllocationID, volume.ID, err)\n\t\t}\n\t}\n\n\tvolume.ModifyIndex = index\n\tvolume.ModifyTime = now\n\n\t// Allocations are copy on write, so we want to keep the Allocation ID\n\t// but we need to clear the pointer so that we don't store it when we\n\t// write the volume to the state store. We'll get it from the db in\n\t// denormalize.\n\tfor allocID := range volume.ReadAllocs {\n\t\tvolume.ReadAllocs[allocID] = nil\n\t}\n\tfor allocID := range volume.WriteAllocs {\n\t\tvolume.WriteAllocs[allocID] = nil\n\t}\n\n\tif err = txn.Insert(TableCSIVolumes, volume); err != nil {","sourceCodeStart":2896,"sourceCodeEnd":2932,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store.go#L2896-L2932","documentation":"During CSIVolumeClaim the store calls volume.Claim(claim, alloc) to record the new claim on the *structs.CSIVolume. If the volume rejects the claim — because it has no free capacity for the requested access mode (e.g. single-writer already claimed, or write capacity exhausted) — the store wraps that rejection in this error and aborts the transaction. The RPC caller (nomad client/node CSI plugin) surfaces it as a failed claim RPC.","triggerScenarios":"An allocation claiming a CSI volume via Node.Batch/CSIVolumeClaim RPC when: the volume already has a writer claim (SingleNodeWriter mode), WriteAllocs is at the volume's capacity per its requested capabilities, the claim's access mode/attachment mode is incompatible, or the alloc is unknown where required.","commonSituations":"Two jobs scheduling against the same single-node-writer volume; volume registered with smaller capacity than the job's declared demand; misconfigured access_mode (e.g. multi-node-single-writer vs single-node-writer) in the volume spec.","solutions":["Check `nomad volume status <id>` for existing claims and the volume's access mode","Use multi-node-reader-only or a separate volume if concurrent access is required","Increase the volume's capacity (CSI controller expand volume) or set explicit volume_capacity_min in the volume spec","Fix the job's volume capability requests to match what the volume supports"],"exampleFix":"# before: job requests write access to an already-claimed volume\nvolume \"db\" { type = \"csi\" ... }\n# after: change access mode to match usage\nvolume \"db\" {\n  type = \"csi\"\n  access_mode     = \"multi-node-multi-writer\"\n  attachment_mode = \"file-system\"\n}","handlingStrategy":"validation","validationCode":"// Before scheduling, check the volume has free claims and compatible mode\nvol, _, err := client.CSIVolumes().Get(volumeID, nil)\nif err != nil { return err }\nif vol.AccessMode == \"single-node-writer\" && len(vol.WriteAllocs) > 0 {\n\treturn fmt.Errorf(\"volume %s already has a writer claim\", volumeID)\n}","typeGuard":"func volumeClaimable(v *api.CSIVolume, wantWrite bool) bool {\n\tif v == nil { return false }\n\tif wantWrite && v.AccessMode == \"single-node-writer\" && len(v.WriteAllocs) > 0 { return false }\n\treturn true\n}","tryCatchPattern":"if err := claimVolume(volID, allocID); err != nil && strings.Contains(err.Error(), \"failed to claim volume\") {\n\t// reschedule elsewhere or use a different volume\n}","preventionTips":["Match job volume capabilities to the volume's registered access mode","Size volumes with volume_capacity_min per job demand","Avoid sharing single-writer volumes across jobs","Check nomad volume status before re-deploying jobs"],"tags":["csi","nomad","volume-claim","capacity"],"backgroundTag":"csi-volume-claim-rejected","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"}