How to Fix Longhorn 'Volume Controller Failed to Attach' When Replica Count Is Zero
Threat/Impact Level: CRITICAL | Downtime Risk: HIGH | Time to Fix: 15–45 mins depending on data recovery path
TL;DR
- What broke: Longhorn has zero schedulable replicas for the volume — all replicas are in
ErrororStoppedstate, so the volume controller cannot attach to any node. - How to fix it: Force-delete faulted replicas, verify node/disk scheduling is enabled, and trigger a replica rebuild or restore from backup.
- Use our Client-Side Sandbox above to paste your Longhorn Volume YAML and auto-generate the corrected spec with proper replica scheduling constraints.
▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]
The Incident (What Does the Error Mean?)
Raw error surface — typically seen in kubectl describe pod or Longhorn Manager logs:
Warning FailedAttachVolume kubelet AttachVolume.Attach failed for volume "pvc-a1b2c3d4":
rpc error: code = Internal desc = failed to attach volume: volume controller failed to attach,
no healthy replica available, replica count: 0And in Longhorn Manager (kubectl logs -n longhorn-system -l app=longhorn-manager):
time="..." level=error msg="failed to attach volume pvc-a1b2c3d4"
reason="replica count is 0, no replica available for scheduling"Immediate consequence: Every pod mounting this PVC is stuck in ContainerCreating or Pending. StatefulSets, databases, and any workload with a volumeMount referencing this PVC are fully down. Kubernetes will not reschedule the pod to another node — it will sit and retry indefinitely.
▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]
The Attack Vector / Blast Radius
This is not a transient blip. Zero replicas means Longhorn has no copy of the volume data it can serve. How you got here matters:
Scenario A — Node mass eviction or cloud provider spot interruption: All nodes hosting replicas were terminated simultaneously. Longhorn marks replicas Error. If replicaCount: 1 was set (anti-pattern), you have zero redundancy and zero recovery path without a backup.
Scenario B — Disk pressure / node taint: Nodes were tainted (node.longhorn.io/create-default-disk: false) or disks were manually disabled in the Longhorn UI. The scheduler cannot place replicas. Existing replicas on those disks go Stopped.
Scenario C — Longhorn upgrade gone wrong: A manager rollout left replica CRDs in an inconsistent state. The engine image mismatch causes replicas to fail health checks.
Blast radius: In a StatefulSet with 10 pods across 10 PVCs, if your storage class has numberOfReplicas: 1 and a single AZ goes down, all 10 volumes hit zero replicas simultaneously. Your entire stateful tier is offline. This cascades to connection pool exhaustion in upstream services within seconds.
How to Fix It
Step 1 — Triage: Identify replica state
# Get volume status
kubectl get volume.longhorn.io -n longhorn-system pvc-a1b2c3d4 -o yaml
# List all replicas for this volume
kubectl get replicas.longhorn.io -n longhorn-system \
-l longhornvolume=pvc-a1b2c3d4 -o wide
# Check node/disk scheduling status
kubectl get nodes.longhorn.io -n longhorn-system -o yaml | \
grep -A5 'allowScheduling'Step 2 — Basic Fix (Re-enable scheduling and force replica rebuild)
# Re-enable disk scheduling on affected node (if disabled)
kubectl patch node.longhorn.io <node-name> -n longhorn-system \
--type=json \
-p='[{"op":"replace","path":"/spec/disks/<disk-id>/allowScheduling","value":true}]'
# Delete all Error/Stopped replicas to force rescheduling
kubectl delete replicas.longhorn.io -n longhorn-system \
-l longhornvolume=pvc-a1b2c3d4
# Longhorn will attempt to schedule new replicas — watch the volume
kubectl get volume.longhorn.io -n longhorn-system pvc-a1b2c3d4 -wIf the volume has salvageable data on a faulted replica, use the Longhorn UI: Volume → Request Last Replica Salvage before deleting replicas.
Step 3 — Enterprise Best Practice (Fix the root cause in the StorageClass)
The real fix is never running numberOfReplicas: 1 for stateful workloads and enforcing node anti-affinity for replica placement.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-production
provisioner: driver.longhorn.io
parameters:
- numberOfReplicas: "1"
+ numberOfReplicas: "3"
- staleReplicaTimeout: "30"
+ staleReplicaTimeout: "2880"
+ replicaAutoBalance: "best-effort"
+ diskSelector: "ssd"
+ nodeSelector: "storage"
fromBackup: ""
reclaimPolicy: Retain
+volumeBindingMode: WaitForFirstConsumerAnd for the Longhorn default settings (applied via kubectl edit settings.longhorn.io -n longhorn-system):
# Setting: default-replica-count
- value: "1"
+ value: "3"
# Setting: replica-soft-anti-affinity
- value: "false"
+ value: "true"
# Setting: replica-zone-soft-anti-affinity
- value: "false"
+ value: "true"💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.
(For CI/CD pipeline automation, install via
npm i -g stackengine).
▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]
Prevention in CI/CD
OPA/Gatekeeper Policy — Block single-replica StorageClasses
package longhorn.storagepolicy
deny[msg] {
input.kind == "StorageClass"
input.provisioner == "driver.longhorn.io"
to_number(input.parameters.numberOfReplicas) < 2
msg := sprintf(
"StorageClass '%v' sets numberOfReplicas < 2. Minimum is 2 for non-dev workloads.",
[input.metadata.name]
)
}Checkov / Helm pre-flight check
# Add to your CI pipeline before helm upgrade
checkov -d ./helm/values.yaml \
--check CKV_LONGHORN_REPLICA_COUNT \
--compactLonghorn Backup Policy (non-negotiable for production)
# Recurring job — snapshot every 1h, backup every 6h, retain 14 days
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: production-backup
namespace: longhorn-system
spec:
cron: "0 */6 * * *"
task: backup
groups:
- default
retain: 56
concurrency: 2Tag all production PVCs with recurring-job-group.longhorn.io/default: enabled so this job picks them up automatically. Without this, zero replicas + no backup = unrecoverable data loss.
Alerting — Don't find out from users
# Prometheus alert rule
- alert: LonghornVolumeReplicaCountCritical
expr: longhorn_volume_robustness == 3 # 3 = Faulted
for: 2m
labels:
severity: critical
annotations:
summary: "Longhorn volume {{ $labels.volume }} is Faulted — replica count may be zero"
runbook: "https://your-wiki/longhorn-replica-recovery"Official Grounding & Normative Specifications
The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:
Official runtime configuration documentation governing lock acquisition timeouts, deadlock detection cycles, and wait logging.
Federal security guidelines for secret exfiltration prevention, automated integrity checks, and peer sign-offs.
Core memory subsystem controls, pressure stall information (PSI), and kernel OOM invocation mechanics.
Industry-standard specification for container execution boundaries and POSIX namespace isolation.