Kubernetes Finalizers Explained: Why Namespaces Get Stuck in “Terminating” State
Finalizers in Kubernetes ensure resources are properly cleaned up before deletion. But when they hang, namespaces or other objects can get stuck in “Terminating.” Here’s how to understand and fix them.

Introduction
If you’ve ever tried to delete a namespace in Kubernetes and found it stuck in the “Terminating” state for what feels like forever, you’re not alone.
It’s one of the most common and frustrating issues DevOps engineers encounter — you type:
kubectl delete ns my-namespace
…and nothing happens. The namespace just hangs there.
When you dig deeper, you’ll usually find something like this in the YAML definition:
metadata:
finalizers:
- kubernetes
- kubernetes.io/some-controller
That’s your culprit — finalizers.
But what are they, why do they exist, and how can you safely debug and remove them? Let’s dive in.
What Are Kubernetes Finalizers?
A finalizer is a special field in Kubernetes object metadata that prevents a resource from being deleted until certain cleanup tasks are completed.
You can think of a finalizer as a “to-do list” for Kubernetes controllers. Before the Kubernetes API Server actually removes an object from etcd (the cluster’s database), it checks the list of finalizers attached to that resource.
Each finalizer entry represents a controller or process responsible for cleaning up associated resources (e.g., cloud volumes, load balancers, secrets, or network attachments). Only when all finalizers are removed can Kubernetes complete the deletion.
Why Finalizers Exist
The purpose of finalizers is safe and predictable cleanup. Without them, deleting a resource could leave behind orphaned or dangling resources — like persistent volumes, cloud network interfaces, or IAM roles.
Common Use Cases for Finalizers
- PersistentVolumeClaims (PVCs) – A finalizer ensures that the associated PersistentVolume (PV) is detached and cleaned up before deletion.
- Namespaces – When you delete a namespace, Kubernetes runs through every resource within it to ensure all sub-resources (Deployments, Services, Secrets, etc.) are also deleted.
- Custom Resource Definitions (CRDs) – CRD controllers (e.g., operators) use finalizers to perform cleanup before the CRD instance disappears.
- Service Controllers – Cloud integrations like AWS Load Balancer Controllers use finalizers to delete cloud load balancers properly.
How Finalizers Work
When a resource is marked for deletion (via kubectl delete), Kubernetes sets a deletion timestamp on the object and stops new operations. However, it won’t actually remove it from etcd until the finalizer list is empty.
Here’s a simplified lifecycle:
- You run kubectl delete on an object.
- Kubernetes adds a deletionTimestamp to the object.
- Controllers responsible for the finalizers see that timestamp and start cleanup.
- Once cleanup is done, the controller removes its own finalizer.
- When the list of finalizers is empty, Kubernetes finally deletes the object.
When Things Go Wrong
Finalizers rely on controllers doing their job. But sometimes, a controller crashes, is removed, or misbehaves. When that happens, Kubernetes waits indefinitely for a cleanup that will never occur — leaving your resource (or namespace) stuck in Terminating.
Typical Symptoms
- Namespace or resource stuck in Terminating state.
- kubectl delete never completes.
- kubectl get namespace <name> -o yaml shows finalizers field still present.
- Logs of relevant controllers show errors or missing references.
Debugging a Stuck Namespace or Resource
Let’s walk through a practical example.
Step 1: Inspect the Namespace
kubectl get ns my-namespace -o yaml
You might see something like:
metadata:
name: my-namespace
finalizers:
- kubernetes
- example.com/custom-cleanup
Step 2: Identify Which Finalizer Is Stuck
Each finalizer usually corresponds to a controller or operator.
Check the controller logs — for example, if it’s a CRD managed by an operator:
kubectl logs -n kube-system deployment/my-operator
You might notice errors like “failed to cleanup resource” or “resource not found.”
Step 3: Remove the Finalizer (Carefully!)
If you’ve confirmed that the cleanup is no longer needed or the responsible controller is gone, you can manually remove the finalizer.
The safest way is via kubectl patch:
kubectl patch ns my-namespace -p '{"metadata":{"finalizers":[]}}' --type=merge
Alternatively, you can edit the resource directly:
kubectl edit ns my-namespace
Then remove the finalizer lines under metadata.finalizers and save.
⚠️ Important: Only do this if you’re absolutely sure it’s safe — otherwise, you could leave behind orphaned resources (like un-deleted load balancers or volumes).
A Real-World Example
Imagine you have a namespace dev-app with workloads managed by the AWS Load Balancer Controller.
When you delete the namespace, you notice it’s stuck in Terminating. Inspecting it shows:
metadata:
finalizers:
- service.kubernetes.io/load-balancer-cleanup
This finalizer tells the controller to delete any associated AWS load balancer before removing the Service object. If the controller is down or permissions are broken (e.g., missing IAM policy), it never removes the finalizer — and your namespace stays stuck.
Fix:
Restart or repair the AWS Load Balancer Controller, then retry deletion.
If that fails, and you’re confident no cloud resources remain, remove the finalizer manually as shown above.
Best Practices for Handling Finalizers
- Avoid manual removal unless necessary.Try to fix the underlying controller issue first.
- Always check controller logs.They often reveal the cause of stuck finalizers.
- Don’t remove all finalizers by default.Some perform critical cleanup that prevents resource leaks.
- Use automation carefully.Some DevOps teams script namespace cleanup, but ensure safeguards exist.
- For CRD developers:If you write a Kubernetes Operator, handle finalizers responsibly — register them on object creation, perform cleanup in your Reconcile logic, and remove them after success.
Conclusion
Finalizers are one of those subtle but powerful Kubernetes mechanisms that ensure cluster resources are cleaned up safely.
They act as “cleanup contracts” between controllers and the API server. However, when those controllers go missing or malfunction, you can end up with stuck resources.
By understanding what finalizers are, why they exist, and how to inspect and remove them safely, you’ll be much better equipped to handle one of Kubernetes’ most common frustrations — the “Terminating” namespace.