{"record":{"id":"4ed44df7f31e4b13","repo":"hashicorp/nomad","slug":"volume-is-currently-unschedulable","errorCode":null,"errorMessage":"volume is currently unschedulable","messagePattern":"volume is currently unschedulable","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/errors.go","lineNumber":92,"sourceCode":"\tErrResultPaginatorCreation = errors.New(errResultPaginatorCreation)\n\n\tErrUnknownNode = errors.New(ErrUnknownNodePrefix)\n\n\tErrDeploymentTerminalNoCancel    = errors.New(errDeploymentTerminalNoCancel)\n\tErrDeploymentTerminalNoFail      = errors.New(errDeploymentTerminalNoFail)\n\tErrDeploymentTerminalNoPause     = errors.New(errDeploymentTerminalNoPause)\n\tErrDeploymentTerminalNoPromote   = errors.New(errDeploymentTerminalNoPromote)\n\tErrDeploymentTerminalNoResume    = errors.New(errDeploymentTerminalNoResume)\n\tErrDeploymentTerminalNoUnblock   = errors.New(errDeploymentTerminalNoUnblock)\n\tErrDeploymentTerminalNoRun       = errors.New(errDeploymentTerminalNoRun)\n\tErrDeploymentTerminalNoSetHealth = errors.New(errDeploymentTerminalNoSetHealth)\n\tErrDeploymentRunningNoUnblock    = errors.New(errDeploymentRunningNoUnblock)\n\n\tErrCSIClientRPCIgnorable  = errors.New(\"CSI client error (ignorable)\")\n\tErrCSIClientRPCRetryable  = errors.New(\"CSI client error (retryable)\")\n\tErrCSIVolumeMaxClaims     = errors.New(\"volume max claims reached\")\n\tErrCSIVolumeUnschedulable = errors.New(\"volume is currently unschedulable\")\n\tErrCSIPluginInUse         = errors.New(\"plugin in use\")\n)\n\n// IsErrNoLeader returns whether the error is due to there being no leader.\nfunc IsErrNoLeader(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), errNoLeader)\n}\n\n// IsErrNoRegionPath returns whether the error is due to there being no path to\n// the given region.\nfunc IsErrNoRegionPath(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), errNoRegionPath)\n}\n\n// IsErrTokenNotFound returns whether the error is due to the passed token not\n// being resolvable.\nfunc IsErrTokenNotFound(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), errTokenNotFound)\n}","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/errors.go#L74-L110","documentation":"ErrCSIVolumeUnschedulable is returned when a volume claim is requested but the volume is not currently schedulable for the requested access mode — its plugin is unhealthy, the node is down, or read/write scheduling capacity is zero (ReadSchedulable/WriteSchedulable returns false). The state store refuses the claim because the volume cannot be served.","triggerScenarios":"CSIVolume.Claim (via structs.CSIVolume.ValidateRequest at csi.go:629/659) when v.ReadSchedulable() or v.WriteSchedulable() is false — e.g. the CSI plugin's health is unhealthy, Schedulable is false, or all topologies/nodes serving the volume are unavailable.","commonSituations":"CSI plugin on the node is unhealthy or the node was drained; storage controller reports the volume as unavailable; plugin capability/Topology mis-match declared in the volume spec; after a node failure the volume has zero schedulable nodes.","solutions":["Check 'nomad plugin status <plugin>' and 'nomad node status' — restore plugin health or bring the node back, then retry the claim","Verify the volume spec's requested capabilities match what the plugin actually advertises (nomad volume inspect)","Fix plugin/controller configuration so the volume is marked schedulable (correct CSI endpoint, healthy controller)","If the volume belongs to a drained/dead node, re-create the volume pointing at a healthy node's plugin"],"exampleFix":"// before\n# volume spec requires write access, but plugin advertises only read\naccess_mode = \"single-node-writer\"\n// after\n# match capabilities to the plugin's advertised CSI capabilities\naccess_mode     = \"single-node-reader-only\"\nattachment_mode = \"file-system\"\n# or fix the plugin so it supports the requested capability","handlingStrategy":"validation","validationCode":"vol, _, err := client.CSIVolumes().Info(volID, nil)\nif err != nil || vol == nil || len(vol.NodesHealthy) == 0 || vol.Schedulable == false {\n    return fmt.Errorf(\"volume %s not schedulable: plugin/node unhealthy\", volID)\n}","typeGuard":"func volumeSchedulable(vol *api.CSIVolume, write bool) bool {\n    if vol == nil { return false }\n    if write { return vol.Schedulable && len(vol.NodesHealthy) > 0 }\n    return vol.Schedulable\n}","tryCatchPattern":"err := claimVolume(volID, allocID)\nif err != nil && strings.Contains(err.Error(), structs.ErrCSIVolumeUnschedulable.Error()) {\n    return fmt.Errorf(\"volume %s unschedulable; check plugin health and node status\", volID)\n}","preventionTips":["Monitor CSI plugin health (nomad plugin status) and node eligibility before scheduling volume jobs","Match requested access_mode/capabilities to what the plugin advertises","Keep the storage controller reachable so volumes stay marked schedulable","Drain/nodes handling: recreate the volume on a healthy node after node loss"],"tags":["csi","storage","nomad","scheduling"],"backgroundTag":"volume-unschedulable","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"}