A CLI tool to diagnose and remediate Kubernetes resources stuck in Terminating state due to unsatisfiable finalizers, missing controllers, deleted CRDs, or blocking webhooks.
If you've ever run kubectl delete namespace and watched it hang forever, you know the frustration. The namespace sits in Terminating state, and you're left searching Stack Overflow for arcane kubectl commands involving finalizers, JSON patches, and API proxies.
I got tired of copy-pasting the same commands over and over, so I built unstuck to automate the diagnosis and remediation process. Instead of manually hunting down stuck resources and crafting patch commands, you can now run a single command to understand what's wrong and fix it safely.
- Diagnose stuck namespaces, CRDs, and resources
- Identify blocking finalizers, discovery failures, and webhook issues
- Generate remediation plans with escalating risk levels
- Execute fixes with dry-run support and audit logging
go install github.com/sozercan/unstuck/cmd/unstuck@latestunstuck diagnose namespace cert-managerExample output:
DIAGNOSIS: Namespace "cert-manager"
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Status: Terminating (since 2h ago)
Root Cause: CR instances stuck with unsatisfied finalizers
BLOCKERS (3 found)
ββββββ¬ββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ¬βββββββββββ
β # β Resource β Finalizer β Status β
ββββββΌββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββΌβββββββββββ€
β 1 β Certificate/my-cert β cert-manager.io/finalizer β Stuck β
β 2 β Certificate/another-cert β cert-manager.io/finalizer β Stuck β
β 3 β Issuer/letsencrypt-prod β cert-manager.io/finalizer β Stuck β
ββββββ΄ββββββββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ΄βββββββββββ
RECOMMENDATION
3 resources are stuck in Terminating. Use `unstuck plan namespace cert-manager` to generate remediation steps.
unstuck diagnose crd certificates.cert-manager.iounstuck diagnose certificate my-cert -n cert-managerunstuck diagnose namespace cert-manager -o json | jq '.blockers | length'unstuck plan namespace cert-managerunstuck apply namespace cert-manager --dry-run# Execute with confirmation prompts
unstuck apply namespace cert-manager
# Skip prompts (for automation)
unstuck apply namespace cert-manager --yesAnalyze a stuck Kubernetes resource (read-only).
unstuck diagnose <type> <name> [flags]Supported types:
namespace/ns- Diagnose a namespacecrd- Diagnose a CustomResourceDefinition<resource>- Diagnose any resource type (e.g.,certificate,pod)
Flags:
-n, --namespace- Namespace for resource targets-o, --output- Output format:text,json(auto-detects TTY)-v, --verbose- Verbose output with conditions
Generate a remediation plan for a stuck resource.
unstuck plan <type> <name> [flags]Flags:
--max-escalation- Maximum escalation level (0-4, default: 2)--allow-force- Allow Level 3-4 actions in the plan
Execute the remediation plan.
unstuck apply <type> <name> [flags]Flags:
--dry-run- Show what would be done without making changes-y, --yes- Skip confirmation prompts--continue-on-error- Continue even if some actions fail--max-escalation- Maximum escalation level (0-4, default: 2)--allow-force- Allow Level 3-4 actions
| Flag | Default | Description |
|---|---|---|
--kubeconfig |
~/.kube/config |
Path to kubeconfig |
--context |
current | Kubernetes context to use |
--timeout |
5m |
Overall operation timeout |
Unstuck uses escalation levels to manage risk:
| Level | Name | Risk | Description |
|---|---|---|---|
| 0 | Informational | None | Diagnosis only |
| 1 | Clean Deletion | Low | Retry with controller |
| 2 | Finalizer Removal | Medium | Remove finalizers from resources |
| 3 | CRD Finalizer | High | Remove CRD cleanup finalizer |
| 4 | Force Finalize | Critical | Force-finalize namespace |
| Code | Meaning |
|---|---|
| 0 | Success / Resource is healthy |
| 1 | Error / Resource not found |
| 2 | Partial success |
- Go 1.25+
- kubectl configured with cluster access
- kind (for integration tests)
make build# Unit tests
make test-unit
# Integration tests (requires kind cluster)
make test-integrationmake lintMIT