Deleting an Argo CD application that will not delete

A stuck Argo CD application delete usually comes from a repository Argo CD can no longer read or from the resources finalizer waiting on managed objects. This page explains how to diagnose each case and clean up without losing the wrong resources.

On this page

Why an Argo CD application will not delete and when to act

An Argo CD Application that stays in a deleting state usually has one of two causes: Argo CD can no longer generate the manifests for the application, usually because its source repository is missing, unreachable, or has changed in a way the repo-server cannot render, or the resources-finalizer.argocd.argoproj.io finalizer is set and Argo CD is still trying to remove the resources it manages. Bring in a partner when the stuck application sits in a production or regulated environment, when the repository itself is in doubt, or when a cleanup has already been attempted and the team cannot tell which managed resources are still live.

The Argo CD FAQ states that Argo CD cannot delete an application whose manifests it cannot generate. That leaves two paths: restore the repository (or the path, branch or revision the Application points to) so the repo-server can render the manifests again, or delete the Application with --cascade=false and remove the managed resources by hand. The second path is a decision with consequences. Before choosing it, confirm which resources the Application owns, who else depends on them, and whether anything outside Git was changed directly in the cluster, because a non-cascading delete leaves those workloads running and unmanaged.

Whether a deletion removes the workloads depends on cascade settings, and those settings are easy to misread. The resources-finalizer.argocd.argoproj.io finalizer, when present on an Application, tells Argo CD to delete its managed resources as part of the delete. Without it, deleting the Application removes only the Application object and leaves the workloads behind. Check the finalizer list and the deletion flags on the Application, and check which tracking method the instance uses, before running any delete command, so the team knows exactly what the next action will remove.

Which causes leave a delete hanging

A deletion that hangs almost always traces back to something Argo CD needs in order to reach or render the application's resources. The causes below fall into two groups: Argo CD cannot generate or reach the manifests it must remove, or a resource refuses to go away. Check them in the order listed so you isolate the blocker before you touch the finalizer.

Missing or deleted Git path

The source repository URL or target path may have been renamed, moved or deleted after the application was created. Argo CD then cannot render the manifests it needs to identify what to remove, so the deletion waits. The symptom is an application whose condition shows a repository or manifest generation error while it sits in a deleting state. First check the application's source fields and confirm the path still exists at the target revision in Git.

Repository credential Secret invalid

Since Argo CD 3.0, repositories must be defined as Kubernetes Secrets rather than entries in the argocd-cm ConfigMap. If that Secret was removed, rotated without updating Argo CD, or labeled incorrectly, the repo-server cannot authenticate and manifests cannot be generated. The symptom is an authentication or repository access error on the application. First check that the repository Secret exists in the Argo CD namespace with the expected label and that its credentials still work.

Helm or Kustomize generation failure

The repo-server runs Helm and Kustomize to render manifests, so a broken chart dependency, missing values file or invalid overlay stops rendering even when Git is reachable. Deletion needs the same rendered output that the last successful sync produced, so a failing render blocks it. The symptom is a manifest generation error in the application details. First run the same Helm template or Kustomize build locally against the revision the application points to.

Resource blocked by another controller

A managed resource can refuse removal when another controller or a validating webhook adds a finalizer or rejects the delete request. Examples include a custom resource whose operator has been removed, or a namespace held by a policy engine. The symptom is a specific child resource that stays in a terminating state while the rest of the application disappears. First check that resource's finalizers and the operator or webhook responsible for them before removing anything by hand.

Destination cluster unreachable

Argo CD removes resources through the API server of the destination cluster. If the cluster is offline, its registration credentials have expired, or the network path from the Argo CD control plane has changed, the controller cannot issue delete calls and the application remains pending. The symptom is a connection or cluster-not-found error against the destination. First confirm the cluster is registered, reachable from the Argo CD namespace and that its credential Secret is still valid.

Cascading, non-cascading and finalizer-free deletes compared

The resources finalizer, resources-finalizer.argocd.argoproj.io, tells Argo CD to delete the resources it manages when the Application is deleted. Argo CD removes the managed objects from the destination cluster first, and only then removes the Application object. The Argo CD cluster bootstrapping guide describes this behavior, which is why the finalizer can also hold an Application in place when Argo CD cannot finish that cleanup.

  • What it removes: every resource in the Application's inventory, including Deployments, Services, ConfigMaps, Secrets and custom resources in the destination namespace or cluster.
  • Data risk: PersistentVolumeClaims and their volumes follow the reclaim policy of the storage class. Confirm that policy before deleting stateful workloads.
  • Hang condition: if the repository or manifests cannot be generated, Argo CD cannot work out what to delete, so the finalizer keeps the Application in the cluster.
  • When to choose it: when the application is retired, its resources were created only by this Application, and stateful data has a current backup or a confirmed plan.

Before deleting, list the resources the Application owns and check whether any of them hold data you need to keep.

How to clean up a stuck delete without losing live workloads

This sequence takes a hung Argo CD Application from diagnosis to removal, so each managed resource is either restored, deliberately kept or deleted on purpose, with a record of what was decided at every step.

  1. Capture the Application manifest and status

    Before changing anything, export the Application object and its status to files kept outside the cluster, for example with kubectl get application <name> -n argocd -o yaml. Record the source repository URL, target revision, path, destination cluster, sync policy and any finalizers. This export is your rollback point if the delete path goes wrong and the only copy of the configuration you will need if you decide to recreate the Application. Done when the file is stored in version control or another backed-up location and you can open it and read the source and destination fields.

  2. Review project RBAC before deleting

    Check the AppProject that owns the Application and list who holds delete and update permissions on it. Since Argo CD 2.14 to 3.0, update and delete RBAC apply only to the application itself, so confirm the policy grants the people and automation involved only what they need. Notify the owning team that a deletion is in progress so no one reapplies the Application mid-procedure. Done when you have a written list of principals with delete rights and the owning team has acknowledged the change window.

  3. Identify managed resources and their owners

    Use the Application's resource tree in the UI or argocd app resources <name> to list every managed object, then check the cluster for objects that carry the Application's tracking annotation but do not appear in the list. For each resource, note its kind, namespace and whether another controller, Helm release or team also manages it. Shared or externally owned resources need a separate decision. Done when you have a complete inventory and each resource has a named owner or a note that it has none.

  4. Attempt to restore the repository or its credentials

    Most hung deletions happen because Argo CD cannot generate manifests, usually after a repository was moved, renamed, deleted or lost its credentials. Check the repository definition, which in Argo CD 3.0 and later lives in a Kubernetes Secret, and confirm the Git URL, the credential and the target revision still resolve. If the repository is back, refresh the Application and confirm the manifests render. Done when argocd app manifests <name> returns output without errors, which means the normal cascading delete can proceed.

  5. Choose between restoring manifests and a non-cascading delete

    If the repository cannot be restored, decide between two paths. Restoring means pointing the Application at a copy of the manifests, which keeps the cascading delete intact and removes resources cleanly. A non-cascading delete with --cascade=false removes the Application object and leaves live resources running, so you must then remove them yourself in the next step. The Argo CD FAQ confirms that this is the route when manifests cannot be generated. Done when the chosen path and its reason are written into the change record and approved by the resource owners.

  6. Remove orphaned resources with a checklist

    If you took the non-cascading path, delete each resource from the inventory in dependency order, typically Services and Ingresses before Deployments and workloads, then PersistentVolumeClaims only after confirming the data is backed up or no longer needed. Tick off each object against the list, record the command used, and confirm the owning team has signed off on each removal. Do not use broad label selectors that could match resources from other applications. Done when every item on the checklist is marked deleted and a fresh list of resources with the tracking annotation returns nothing for this Application.

  7. Remove the Application and verify nothing remains

    Delete the Application object, and confirm whether the resources finalizer is present, since the Argo CD cluster bootstrapping guide describes it as deleting managed resources when the Application is deleted. Once the Application is gone, search the namespaces it targeted for leftover objects, check for orphaned secrets, and confirm the destination cluster shows no remaining workloads for it. Keep the exported manifest from step one with the change record. Done when the Application no longer appears in kubectl get applications -n argocd, no tracked resources remain, and the record is filed.

Who can delete an application after the 3.0 RBAC change

Since the 2.14 to 3.0 upgrade, update and delete RBAC apply only to the application itself. A permission to delete an Application object does not extend to the resources that application manages, and it does not grant access to pod logs. Teams that assumed a delete right covered the workloads underneath will find that cleanup stalls or that a person can remove the Application while still lacking the rights to inspect what it controls. Before anyone runs a stuck deletion, confirm that the person has delete on the application in the applications resource for the right project, and separately confirm get on logs if they need to read pod output while diagnosing the hang. The Argo CD 2.14 to 3.0 upgrade notes describe this change, and the exact policy lines should be checked against your own argocd-rbac-cm before you rely on them.

To check the effective permissions, ask the operator to attempt the action in a non-production Argo CD instance or with a test Application in the same project, and review the RBAC configuration with whoever owns the SSO group mappings. Confirm that the account's role comes from the group claim your identity provider sends, because a user who has lost a group membership can appear to have rights that have already been removed. Also confirm which Argo CD project the Application belongs to, since project roles and destination restrictions determine what the operator can touch. Record who approved the deletion and the reason for it, ideally in the ticket that also tracks the change.

Deletions should be traceable outside the cluster. The Application manifest should live in Git, so removing it there, through a reviewed pull request, creates a history that shows who asked for the removal and when. Argo CD's own audit trail is useful only if you have confirmed that API and sync events reach a log store you control, and that the retention period meets your change management policy. Ask your platform team which audit sources are enabled, how long they are kept, and whether a deletion performed with kubectl leaves an entry that someone can find later. Do not rely on memory or chat messages as the record of who removed a production Application.

Security and operational risks during forced cleanup

A deletion that hangs tempts teams to remove finalizers, switch to non-cascading deletes or edit repositories under pressure. Each shortcut changes who owns cluster state and what Argo CD can still verify, so the cards below cover the places where a fast fix creates a slower incident.

Orphaned objects after finalizer removal

Removing the resources-finalizer.argocd.argoproj.io finalizer lets the Application disappear while its managed resources keep running. Nothing in Argo CD then reconciles or prunes those objects, so they can continue to serve traffic with no owner. Before removing the finalizer, list the resources the Application tracks, record which ones must survive, and assign each to a named team or a follow-up change.

Live credentials after non-cascading deletes

A delete with --cascade=false removes the Application and leaves its resources in place. Secrets, service accounts, ingress rules, network policies and load balancers may remain active and still grant access. Treat each leftover credential as live until it is rotated or removed, and confirm with the owning team that nothing downstream depends on it.

Secret exposure during incident edits

Editing repository definitions or Secrets under time pressure can expose credentials in shell history, ticket comments, or copied manifests. Argo CD redacts cluster, Git and OAuth2 credentials from API responses and logs, but that protection does not cover values pasted into external tools. Use the cluster's own access controls for these edits, keep the change in a ticket, and rotate any value that was displayed or copied.

Untrusted repository content during restore

The repo-server runs Helm and Kustomize against repository content, so restoring a repository from an unverified fork or mirror can execute untrusted logic inside the cluster's Argo CD context. Restore from the approved source, confirm the commit being used, and check that out-of-tree file access is restricted before the application is allowed to generate manifests again.

Access that bypasses audit trails

Forced cleanup often runs with cluster-admin rights outside the normal Argo CD workflow. Only the admin account or a privileged kubeconfig may be able to remove the finalizer, which can leave no Git commit and no Argo CD record of the change. Confirm which identities can perform these steps, require the action be logged in a ticket, and disable the built-in admin user once SSO is configured.

Questions teams ask about stuck Argo CD deletes

How long does a stuck Argo CD application delete take to resolve?

No supplied fact gives a duration, so the honest answer depends on the cause. A delete blocked by a missing or broken repository can often be resolved quickly once the repository is restored, because Argo CD can then generate manifests and remove resources. A delete that requires manual cleanup of orphaned resources takes longer, because each resource must be inventoried, checked for dependencies and removed in order. The main drivers are the number of managed resources, whether stateful data sits behind them, whether other teams depend on them, and how many approvals the change needs. Ask any provider to break the estimate down by those drivers and to state what assumptions it depends on.

Can our own team fix a stuck Argo CD delete without a partner?

Often yes, if the team understands the cause and has the access to act on it. The Argo CD FAQ describes two paths: restore the repository so manifests can be generated again, or delete the Application with --cascade=false and remove resources manually. The second path is where mistakes happen, because removing the wrong object can cause an outage. A partner adds value when many applications are affected, when the cluster holds stateful workloads, when audit evidence of the cleanup is required, or when the internal team lacks time for a careful review. Decide based on blast radius and the team's current capacity.

What does the work require from our team?

The team needs to provide access and a planned window. Typical requirements include:

  • Admin-level access to the Argo CD instance and the destination clusters, scoped through a change ticket
  • Read access to the source repositories and the ability to restore or reconnect them
  • A current backup of the Application manifests, the relevant namespaces and any persistent data
  • A named owner for each workload who can confirm whether it may be removed
  • A change window in which dependent services can be checked before and after the cleanup

Ask the provider to list exactly which access it needs and to confirm that it will not keep standing credentials after the work ends.

What does a fixed-scope Argo CD cleanup engagement cover?

A fixed-scope cleanup covers the agreed applications, clusters and namespaces named in the written scope, along with the deliverables and timeline agreed before work starts. Typical items include diagnosing the blocking cause, restoring or replacing the source repository, planning the order of resource removal, executing the cleanup with rollback points, verifying that no orphaned objects remain, and documenting what changed. DeployOpen does not publish a price list. To get a quote, ask for a written scope that lists applications and clusters, the cause analysis method, the backup approach, the verification steps, and the handover documentation. The quote then follows from that scope.

Is it ever safe to remove the resources finalizer?

Removing the finalizer can be a reasonable step, but only after the team knows what the finalizer would have done. The resources-finalizer.argocd.argoproj.io finalizer tells Argo CD to delete the managed resources when the Application is deleted. Removing it lets the Application object disappear while its resources stay running, which leaves orphaned workloads that no longer have a GitOps owner. Before removing it, confirm that the resources should survive, record what they are, and plan how they will be managed or removed later. Treat the finalizer as a deliberate decision, not a shortcut to clear an error.

How do we stop stuck deletes from happening again?

Most recurrences come from repositories that are removed, renamed, made private or changed in ways that break manifest generation. Protect the source repositories with explicit ownership, change review and access controls that match how the Application is used. Store repository credentials as Kubernetes Secrets, since Argo CD 3.0 removed repository configuration from the argocd-cm ConfigMap. Limit who can delete Applications through RBAC, keeping in mind that update and delete permissions now apply only to the application itself. Add a review step to the decommissioning process so that Applications are removed before their source is retired. Confirm the exact RBAC and repository settings for your installed version before relying on them.

Designing deletes so they do not hang

The most effective fix for a stuck delete happens before anyone runs argocd app delete. Argo CD can only delete an application whose manifests it can generate, so the repository that holds the manifests and the credential Secrets that let the repo-server read it should be managed under change control, with the same review rules as the workloads themselves. Store repository definitions as Kubernetes Secrets in Git-managed configuration, record who may rotate them, and make sure removing a repository is a deliberate, reviewed change rather than a side effect of a cleanup. A repository that disappears or a token that expires while the application still exists is the most common reason a delete later stops at the generation step.

Decide for each application whether the resources-finalizer.argocd.argoproj.io finalizer belongs in its template. With the finalizer, deleting the Application also deletes the resources it manages, which suits short-lived environments such as preview or test namespaces. Without it, the Application can be removed while workloads keep running, which suits shared databases, stateful services and anything owned by another team. Applying the finalizer to every application by default turns a routine removal into an outage, so set it per application and document the choice in the project so reviewers can see it. The Argo CD cluster bootstrapping guide explains how the finalizer is declared and where it fits in an App of Apps layout.

Separate ownership of the Argo CD Application objects from ownership of the resources they manage. The team that can delete an Application should not automatically be the team that owns the data behind it, and the RBAC rules in the Argo CD project should reflect that split. Before go-live, rehearse a full deletion in a non-production cluster that mirrors the production repository layout, including a deliberate test where the repository is unavailable, so the team learns which path it will take under pressure. Confirm with your own environment which resources the finalizer will remove, and record the approved cleanup steps for the non-cascading case so nobody improvises them during an incident.

How DeployOpen scopes and delivers stuck-delete cleanup

DeployOpen treats a stuck Argo CD application deletion as a scoped piece of recovery work inside your own cluster and Git environment. We confirm what is blocking the delete, agree the cleanup steps in writing, and document how the remaining resources were handled.

How we scope

  • Confirm whether the source repository, credentials or manifest generation failure is what blocks the delete
  • Inventory the application's managed resources, finalizers and owning Argo CD projects before any deletion
  • Agree in writing whether resources are removed through cascade or handled manually with non-cascading deletes

How we build

  • Restore the repository access or manifest source first where that is safe, so Argo CD can generate and delete normally
  • Plan any cascade=false cleanup step by step, recording which resources are removed and which are kept
  • Test the deletion procedure in a non-production cluster before running it against production applications

How we hand over

  • Deliver a runbook covering the checks, commands and approval points used to clear the stuck application
  • Provide a record of removed, orphaned and retained resources with the reasons for each decision
  • Document the Git and RBAC controls that should prevent the same blockage from recurring

How we support

  • Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts
  • Ongoing support, upgrades and continuous testing are available as a retainer for your Argo CD estate
  • Ask any partner to confirm which cluster, repository and recovery access they need before the engagement begins

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.