Problem – LangChain PVC Stuck in Pending After Deployment
When deploying LangChain components (e.g., the vector‑store or document‑loader pods) on a managed Kubernetes cluster with dynamic storage provisioning enabled, the associated PersistentVolumeClaim (PVC) often remains in the Pending state. The pod cannot start, leading to crash loops and a non‑functional AI workflow.
Typical symptoms observed in the cluster:
- Pod status:
CrashLoopBackOfforInit:0/1because the volume cannot be mounted. - PVC description shows
status: Pendingand no bound PV. - Controller manager logs contain errors such as:
persistentvolumeclaim "langchain-vectorstore-pvc" is not bound: no persistent volumes available for claim
failed to provision volume with storage class "standard-rwo": storageclass.storage.k8s.io "standard-rwo" not found
error creating volume: failed to create volume for claim "langchain-vectorstore-pvc": insufficient quota
Root Cause Analysis
1. StorageClass name mismatch
LangChain’s Helm chart (see GitHub repository) defaults to storageClassName: "standard-rwo" for read‑write‑once (RWO) volumes. On many managed clusters (GKE, AKS, OpenShift) the available provisioner is named standard or managed-premium. When the PVC references a non‑existent class, the dynamic provisioner never triggers, leaving the claim pending.
2. Access‑mode incompatibility
Some environments expose only ReadWriteMany (RWX) storage (e.g., Azure managed-premium), while LangChain requests ReadWriteOnce (RWO). The provisioner cannot satisfy the claim, resulting in the same pending state.
3. Disabled dynamic provisioning or missing quota
In OpenShift projects where allowVolumeExpansion is false or the namespace lacks a default StorageClass, the PVC will not be auto‑bound. Additionally, insufficient storage quota will cause the provisioner to reject the request.
These root causes align with real incidents documented in the evidence package: the GKE incident with standard-rwo vs standard, the AKS case with RWX vs RWO, and the OpenShift namespace lacking a provisioner.
Investigation and Debugging Steps
Step 1 – Inspect the PVC
kubectl get pvc -n langchain -o wide
Sample output:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
langchain-vectorstore-pvc Pending <none> 10Gi RWO standard-rwo 2m
Step 2 – Verify available StorageClasses
kubectl get storageclass
Typical output on GKE:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
standard pd.csi.storage.googleapis.com Delete Immediate true 45d
standard-rwo pd.csi.storage.googleapis.com Delete Immediate true 45d
If the expected class is missing, the PVC cannot bind.
Step 3 – Check controller manager logs for provisioning errors
kubectl logs -n kube-system -l component=controller-manager -c kube-controller-manager --tail=100
Search for the PVC name or the storage class name.
Step 4 – Validate namespace quota
kubectl describe quota -n langchain
Look for storage limits and used values.
Step 5 – Confirm access‑mode support
kubectl get sc standard -o yaml | grep -i accessModes
Some cloud‑providers expose only ReadWriteMany for certain classes.
Resolution – Making the PVC Bind
Option A: Align StorageClass name
Update the Helm values (or raw manifest) to reference an existing class.
Before (default values.yaml excerpt):
persistence:
enabled: true
storageClassName: "standard-rwo"
accessModes:
- ReadWriteOnce
size: 10Gi
After – set to the cluster’s default class (standard) or any class that exists:
persistence:
enabled: true
storageClassName: "standard"
accessModes:
- ReadWriteOnce
size: 10Gi
Apply the change:
helm upgrade langchain ./langchain-chart -f values.yaml
Option B: Adjust Access Mode to match provisioner
If only RWX is offered (e.g., Azure managed-premium), modify the claim:
persistence:
enabled: true
storageClassName: "managed-premium"
accessModes:
- ReadWriteMany
size: 10Gi
Option C: Create a static PersistentVolume (OpenShift case)
When dynamic provisioning is disabled, define a PV that satisfies the claim:
apiVersion: v1
kind: PersistentVolume
metadata:
name: langchain-static-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
storageClassName: "manual"
hostPath:
path: /mnt/data/langchain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: langchain-vectorstore-pvc
namespace: langchain
spec:
storageClassName: "manual"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Apply both objects, then redeploy the pod.
Option D: Increase quota or enable dynamic provisioning
If logs indicate “insufficient quota”, request a larger quota from the cloud provider or clean up unused PVCs.
Verification – Confirming the Fix
- Re‑query the PVC:
kubectl get pvc -n langchain langchain-vectorstore-pvc -o yaml
Expected status.phase should be Bound and a volumeName populated.
- Check the pod status:
kubectl get pod -n langchain -l app=langchain-vectorstore
Pod should transition to Running without mount errors.
- Inspect container logs for successful start‑up messages (see LangChain deployment guide).
kubectl logs -n langchain -l app=langchain-vectorstore --tail=20
Typical success line:
INFO: Vector store initialized with persistent volume /data/vectorstore
Prevention – Operational Guardrails
- Validate manifests against the cluster’s storage catalog before applying. Automate with
kubectl apply --dry-run=client -kand a CI check that runskubectl get storageclassto ensure the referenced class exists. - Standardize a default StorageClass in each environment (GKE:
standard, AKS:managed-premium) and pin the LangChain chart to that name via Helm values. - Document required access mode per cloud provider. For multi‑node deployments that need shared storage, override
accessModestoReadWriteManyexplicitly. - Enable quota monitoring and set alerts on PVC creation failures using the
kube_persistentvolumeclaim_status_phasemetric. - Run a post‑deployment sanity check that queries all PVCs in the
langchainnamespace and fails the CI pipeline if any remainPendingafter a configurable timeout.
FAQ – Common Follow‑Up Questions
- Why does the PVC bind on my local minikube cluster but stay pending on GKE?
Because minikube ships with a defaultstandardStorageClass that matches the chart’s default, while GKE may only havestandard-rwoor a custom class. The mismatch prevents dynamic provisioning. - Can I use a ReadWriteMany class with LangChain’s vector store?
Yes. OverrideaccessModes: ["ReadWriteMany"]and ensure the underlying provisioner supports RWX (e.g., Azure Files). The application will treat the volume as a shared directory. - What does “failed to provision volume with storage class … not found” mean?
The controller manager attempted to locate aStorageClassobject with the name specified in the PVC but could not find it. This is usually a typo or a class that was not created in the cluster. - How do I troubleshoot “insufficient quota” errors?
Runkubectl describe quota -n <ns>to see current usage. If the requested size exceeds the quota, request an increase from the cloud admin or delete unused PVCs. - Is it safe to change the storage class of an existing PVC?
Kubernetes does not allow changing thestorageClassNameof a bound PVC. You must delete the PVC (and any dependent pod) and recreate it with the correct class, or migrate data to a new PVC.
Related Topic Hub: RAG Systems Troubleshooting Hub