Fixing the 'No StorageClass Set' Error: Why Your Kubernetes PVC is Stuck in Pending

beginner☸️ Kubernetes2026-04-12| Kubernetes (EKS, GKE, AKS, On-prem clusters), kubectl CLI

Error Message

persistentvolumeclaims "my-pvc" is forbidden: no persistent volumes available for this claim and no storage class is set
#kubernetes#pvc#devops#storageclass#troubleshooting

The Error MessageIt is a common headache: you deploy a stateful application, but your PersistentVolumeClaim (PVC) refuses to budge from a Pending state. When you dig deeper using kubectl describe pvc <pvc-name>, you hit this specific wall:

persistentvolumeclaims "my-pvc" is forbidden: no persistent volumes available for this claim and no storage class is set

What is actually happening?Kubernetes is essentially telling you it has no idea where to put your data. Think of a PVC as a ticket for a seat at a theater. If the theater hasn't built any seats (Static Provisioning) and there is no automated machine to build one for you (Dynamic Provisioning), you are left standing in the lobby.

This error typically crops up for three reasons:

  • Missing Default: Your cluster lacks a designated "Default" StorageClass.- Empty Manifests: Your PVC YAML doesn't specify a storageClassName, leaving Kubernetes to guess.- Manual Mismatch: You created a PersistentVolume (PV) manually, but its size (e.g., 5Gi) or AccessMode doesn't match what the PVC asked for (e.g., 10Gi).## Solution 1: Assign a Default StorageClassMost managed services like AWS EKS or Google GKE come with storage drivers pre-installed, but they might not be set as the default. By marking a class as default, any PVC that doesn't ask for a specific type will automatically use this one. Start by listing your available classes:
kubectl get storageclass

If you see a class like gp2 (on AWS) or standard (on GKE) but it doesn't say (default), run this command to fix it:

kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

Once patched, delete your stuck PVC and recreate it. It should bind almost instantly.

Solution 2: Explicitly Define storageClassNameSometimes you don't want a global default. You might need high-performance SSDs for a database but cheap HDD storage for logs. In this case, you must tell the PVC exactly which "template" to use.

Update your pvc.yaml to include the storageClassName field:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: database-storage
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: premium-r3 # Use your specific class name here
  resources:
    requests:
      storage: 20Gi

Apply the update. Kubernetes will now reach out to the specific CSI driver (like the EBS or Azure Disk driver) to provision that 20Gi volume.

Solution 3: Manual Provisioning for Bare MetalIf you are running a home lab or a bare-metal cluster without a cloud provider, dynamic provisioning isn't available out of the box. You have to be the "storage machine" yourself.

Create a manual PersistentVolume that matches your claim's requirements:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-01
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: "/mnt/data/mysql"

Pro tip: For the PVC to claim this manual volume, ensure the storageClassName in your PVC is either empty ("") or matches the class name you give to the PV.

Verifying the FixAfter applying one of these fixes, check your PVC status again:

kubectl get pvc

You are looking for the Bound status. It looks like this:

NAME             STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
database-storage Bound    pvc-8a7b6c...    20Gi       RWO            premium-r3     15s

If the status is Bound, your Pods will finally move from ContainerCreating to Running.

Prevention Tips- One Default Only: Never set two StorageClasses as default. It confuses the scheduler and can lead to unpredictable provisioning.- Check the Driver: If you have a StorageClass but it still fails, ensure the provisioner pod (like ebs-csi-controller) is actually running in the kube-system namespace.- Watch Your Quotas: On cloud providers, ensure you haven't hit your account limit for IOPS or total disk capacity.

Related Error Notes