Kubernetes Namespace Stuck in Terminating State — Fix
Your namespace has been Terminating for hours. kubectl delete won't help. Here's exactly why this happens and how to force-remove a stuck namespace safely.
You deleted a namespace. It's been "Terminating" for 30 minutes. kubectl delete namespace hangs. Recreating it gives an error. This is one of the most common Kubernetes stuck states.
Here's the fix.
Why Namespaces Get Stuck
When you delete a namespace, Kubernetes needs to delete all resources inside it. It gets stuck when:
- Finalizers — resources have finalizers that haven't been removed
- CRD resources — custom resources whose controller is already deleted
- API aggregation issues — API service is unavailable, can't clean up
The namespace enters Terminating but can't complete because something blocks it.
Diagnose
# Check what's blocking
kubectl get namespace my-namespace -o json | jq '.spec.finalizers'
# ["kubernetes"] ← This is normal, means cleanup in progress
# Check for stuck resources
kubectl api-resources --verbs=list --namespaced -o name | \
xargs -I{} kubectl get {} -n my-namespace --ignore-not-found 2>/dev/null
# Check for resources with finalizers
kubectl get all -n my-namespace -o json | \
jq '.items[] | select(.metadata.finalizers != null) | {kind: .kind, name: .metadata.name, finalizers: .metadata.finalizers}'Fix 1: Remove Resource Finalizers (Most Common)
# Find resources with finalizers in the stuck namespace
for resource in $(kubectl api-resources --verbs=list --namespaced -o name); do
kubectl get $resource -n my-namespace -o json 2>/dev/null | \
jq -r '.items[] | select(.metadata.finalizers != null) | "\(.kind)/\(.metadata.name)"'
done
# Remove finalizer from a specific resource
kubectl patch <resource-type>/<resource-name> -n my-namespace \
-p '{"metadata":{"finalizers":null}}' \
--type=mergeExample — removing finalizer from a stuck PVC:
kubectl patch pvc my-pvc -n my-namespace \
-p '{"metadata":{"finalizers":null}}' \
--type=mergeFix 2: Force-Delete the Namespace (Nuclear Option)
If fixing individual resources is too tedious:
# Export current namespace state
kubectl get namespace my-namespace -o json > /tmp/ns.json
# Remove the finalizer from the spec
cat /tmp/ns.json | jq 'del(.spec.finalizers)' > /tmp/ns-clean.json
# Use kubectl proxy to bypass API
kubectl proxy &
PROXY_PID=$!
# Finalize the namespace via API
curl -s -o /dev/null -w "%{http_code}" \
-H "Content-Type: application/json" \
-X PUT \
--data-binary @/tmp/ns-clean.json \
http://127.0.0.1:8001/api/v1/namespaces/my-namespace/finalize
kill $PROXY_PIDThis tells Kubernetes "cleanup is done" even if it's not — the namespace deletes immediately.
Fix 3: CRD Resources Without Controllers
If you deleted a CRD (Custom Resource Definition) before deleting the custom resources in namespaces, those resources are orphaned with no controller to handle their finalizers.
# Find stuck CRD resources
kubectl get <crd-resource-name> -n my-namespace
# Remove finalizers
kubectl patch <crd-resource-name>/<resource-name> -n my-namespace \
--type json \
-p '[{"op":"remove","path":"/metadata/finalizers"}]'Or patch all instances:
for resource in $(kubectl get <crd-resource-name> -n my-namespace -o name); do
kubectl patch $resource -n my-namespace \
-p '{"metadata":{"finalizers":null}}' --type=merge
doneFix 4: APIService Issue
Sometimes an APIService (extended API) is unavailable, blocking namespace cleanup:
# Check APIService health
kubectl get apiservice | grep False
# v1beta1.metrics.k8s.io False (ServiceNotFound) ← This can block namespace deletion
# Delete broken APIService if it's no longer needed
kubectl delete apiservice v1beta1.metrics.k8s.ioAutomate with a Script
#!/bin/bash
# force-delete-namespace.sh
NAMESPACE=$1
if [ -z "$NAMESPACE" ]; then
echo "Usage: $0 <namespace>"
exit 1
fi
echo "Force-deleting namespace: $NAMESPACE"
# Remove finalizers from all resources in namespace
echo "Removing finalizers from resources..."
for resource_type in $(kubectl api-resources --verbs=list --namespaced -o name 2>/dev/null); do
for resource in $(kubectl get "$resource_type" -n "$NAMESPACE" -o name 2>/dev/null); do
kubectl patch "$resource" -n "$NAMESPACE" \
-p '{"metadata":{"finalizers":null}}' \
--type=merge 2>/dev/null
done
done
# Force finalize namespace
echo "Finalizing namespace..."
kubectl get namespace "$NAMESPACE" -o json | \
jq 'del(.spec.finalizers)' | \
kubectl replace --raw "/api/v1/namespaces/$NAMESPACE/finalize" -f -
echo "Done. Check: kubectl get namespace $NAMESPACE"chmod +x force-delete-namespace.sh
./force-delete-namespace.sh my-stuck-namespacePrevention
Always delete CRD resources before deleting CRDs:
# Delete resources first
kubectl delete <custom-resource-name> --all -n my-namespace
# Then delete the CRD
kubectl delete crd <crd-name>When using Helm with CRDs: Helm doesn't delete CRD resources automatically. Clean up manually before helm uninstall.
The nuclear option (patching namespace finalizers via API) works every time but bypasses Kubernetes' cleanup mechanisms. Use it only when the namespace truly needs to go and you've verified there's no real cleanup blocking it.
Master Kubernetes troubleshooting with real cluster labs at KodeKloud.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
ArgoCD App of Apps Not Syncing — Every Fix (2026)
Your ArgoCD App of Apps pattern stopped syncing. Child apps aren't created, parent shows OutOfSync, or sync is stuck. Here are every cause and the exact fix.
ArgoCD Image Updater Not Syncing — Fix Guide
ArgoCD Image Updater detects a new image tag but doesn't update the Application. Here's how to diagnose and fix annotation errors, registry auth issues, write-back problems, and sync failures.
AWS EKS Cluster Autoscaler Not Scaling — Every Fix (2026)
Your EKS Cluster Autoscaler isn't scaling up, scale-down isn't working, or nodes spin up but stay empty. Here's every cause and the exact fix.