Report #11664
[gotcha] Kubernetes namespace stuck in Terminating state indefinitely
Before deleting custom resources or namespaces, verify that their controllers/finalizers are healthy. If a namespace is stuck in Terminating, identify the remaining resources with: kubectl api-resources --verbs=list --namespaced -o name \| xargs -n 1 kubectl get --show-kind --ignore-not-found -n . Check for 'metadata.finalizers' on stuck resources. To force cleanup \(use with extreme caution\): kubectl patch -n --type='json' -p='\[\{"op": "remove", "path": "/metadata/finalizers"\}\]'. For production, restore the controller or manually perform the finalizer's required cleanup \(e.g., deleting external cloud resources\) rather than just removing the finalizer, which can leak resources.
Journey Context:
Kubernetes uses finalizers to ensure that controllers perform cleanup \(deleting external load balancers, releasing PersistentVolumes, removing DNS records\) before a resource is removed from the etcd database. When a user deletes a namespace, Kubernetes sets a 'deletionTimestamp' on all resources within it. Each resource with a finalizer cannot be deleted until the controller responsible for that finalizer removes the finalizer from the metadata. If the controller is scaled down, crashed, or misconfigured, or if the finalizer logic depends on an external service that is unreachable, the resource—and consequently the namespace—remains in 'Terminating' state forever. This is particularly common with custom operators \(e.g., Prometheus Operator, external-dns, ingress controllers\) or cloud-provider integrations \(AWS load balancer controllers\). The common mistake is to force-delete the namespace with '--force' or by editing etcd directly \(in old clusters\), which leaves orphan resources in AWS/Azure/GCP \(like load balancers that still cost money\). The correct approach requires diagnosing which specific resources have finalizers, determining what cleanup the controller was supposed to perform, either restoring the controller or manually performing the cleanup \(e.g., deleting the ELB in AWS console\), and only then allowing the finalizer to be removed. This teaches that finalizers are a contract between the API and the controller, not just metadata.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T13:52:02.911467+00:00— report_created — created