DevOpsil
Platform Engineering
82%
Needs Review

ArgoCD Application Stuck In Progressing State: Debugging Sync Failures And Manual Recovery Steps

Majid Iqbal NayyarMajid Iqbal Nayyar7 min read

ArgoCD Application Stuck in Progressing State: Debugging Sync Failures and Manual Recovery Steps

If you've worked with ArgoCD for any meaningful amount of time, you've probably stared at that dreaded "Progressing" status, watching your application sync hang indefinitely while your deployment pipeline backs up behind it. As someone who's spent countless hours debugging these scenarios, I can tell you that ArgoCD's sync failures are often cryptic, but they're usually fixable once you know where to look.

The "Progressing" state is ArgoCD's way of saying "I'm trying, but something's not quite right." Unlike a clean failure, this limbo state can persist for hours, leaving you wondering if you should wait it out or intervene. Let's dive into the most common causes and, more importantly, how to get your deployments unstuck.

Understanding the Progressing State

ArgoCD applications get stuck in "Progressing" when the sync operation starts but can't complete successfully. This typically happens during the three-way merge process where ArgoCD compares your Git state, live cluster state, and desired state. When these don't align as expected, or when Kubernetes resources are slow to reconcile, you end up in this frustrating middle ground.

The key difference between "Progressing" and "Synced" is that ArgoCD has initiated changes but hasn't received confirmation that all resources have reached their desired state. This could be due to:

  • Resource dependencies not being met
  • Slow-starting containers or failed health checks
  • Network policies blocking communication
  • Resource quotas being exceeded
  • Webhook failures or validation errors

Common Culprits Behind Sync Failures

1. Health Check Timeouts

The most frequent cause I see is applications with custom health checks that take longer than ArgoCD's default timeout. This is especially common with databases, message queues, and other stateful services that need time to initialize.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: postgres-app
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
    # Increase timeout for slow-starting services
    - Timeout=600s
  # Custom health check configuration
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /spec/replicas

2. Resource Ordering Issues

Kubernetes doesn't guarantee resource creation order, but some applications require specific sequencing. I've seen this break ArgoCD syncs when, for example, a ConfigMap needs to exist before a Deployment references it.

# Use sync waves to control order
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
  annotations:
    argocd.argoproj.io/sync-wave: "2"  # Deploy after wave 1
spec:
  # ... deployment spec
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  annotations:
    argocd.argoproj.io/sync-wave: "1"  # Deploy first
data:
  config.yaml: |
    # ... config data

3. Webhook and Admission Controller Conflicts

Custom admission controllers or mutating webhooks can modify resources during creation, causing ArgoCD to see a drift between desired and actual state. This creates an endless sync loop.

# Ignore fields that webhooks commonly modify
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
spec:
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /spec/template/metadata/annotations
    - /spec/template/spec/securityContext
  - group: ""
    kind: Service
    jsonPointers:
    - /spec/clusterIP

Debugging Techniques That Actually Work

1. Use ArgoCD CLI for Real-time Insights

The web UI is pretty, but the CLI gives you the raw details you need for debugging:

# Get detailed sync status
argocd app get my-app --show-operation

# Watch sync progress in real-time
argocd app sync my-app --async
argocd app wait my-app --timeout 300

# Get detailed resource status
argocd app resources my-app --output wide

2. Examine Resource Events

Kubernetes events are goldmines for debugging sync issues:

# Check events for the application namespace
kubectl get events -n my-app-namespace --sort-by='.lastTimestamp'

# Focus on warning and error events
kubectl get events -n my-app-namespace --field-selector type=Warning

# Get events for specific resources
kubectl describe deployment my-app -n my-app-namespace

3. Analyze ArgoCD Controller Logs

The application controller logs contain detailed information about why syncs fail:

# Get ArgoCD application controller logs
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller -f

# Filter for your specific application
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller | grep "my-app"

Look for patterns like:

  • "failed to sync application"
  • "health check failed"
  • "hook failed"
  • "timeout"

Manual Recovery Strategies

1. Force Refresh and Hard Sync

Sometimes ArgoCD just needs a gentle push to reassess the situation:

# Force refresh the application state
argocd app get my-app --refresh --hard-refresh

# Perform a hard sync (ignore differences)
argocd app sync my-app --force --replace

The --replace flag tells ArgoCD to delete and recreate resources rather than trying to patch them. Use this carefully, especially with stateful resources.

2. Selective Resource Sync

When only specific resources are problematic, sync them individually:

# Sync only specific resources
argocd app sync my-app --resource apps:Deployment:my-app-deployment
argocd app sync my-app --resource v1:Service:my-app-service

# Skip problematic resources temporarily
argocd app sync my-app --resource-exclude apps:Deployment:problematic-deployment

3. Reset Application State

For severely stuck applications, sometimes you need to reset the sync state entirely:

# Terminate any ongoing sync operations
argocd app terminate-op my-app

# Reset the application to a clean state
argocd app delete my-app --cascade=false
argocd app create -f my-app.yaml

Preventive Measures and Best Practices

1. Implement Proper Health Checks

Don't rely on ArgoCD's default health checks for complex applications. Define custom health checks that actually verify your service is ready:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
spec:
  # Custom health check
  healthCheck:
    httpHeaders:
    - name: Accept
      value: application/json
    path: /health
    port: 8080
    scheme: HTTP
    initialDelaySeconds: 30
    periodSeconds: 10
    timeoutSeconds: 5

2. Use Sync Waves and Hooks Strategically

Plan your resource deployment order using sync waves and implement hooks for critical operations:

# Pre-sync hook for database migration
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
  template:
    spec:
      containers:
      - name: migrate
        image: my-app:latest
        command: ["python", "manage.py", "migrate"]
      restartPolicy: Never

3. Configure Reasonable Timeouts

Set appropriate timeouts based on your application characteristics:

apiVersion: argoproj.io/v1alpha1
kind: Application
spec:
  syncPolicy:
    syncOptions:
    - Timeout=300s  # 5 minutes for most apps
    # For databases or complex services:
    # - Timeout=900s  # 15 minutes
    retry:
      limit: 3
      backoff:
        duration: 30s
        factor: 2
        maxDuration: 5m

When to Seek Help vs. When to Force

Knowing when to wait and when to intervene is crucial. Here's my rule of thumb:

Wait it out if:

  • It's been less than your configured timeout
  • Logs show progress (pods starting, health checks running)
  • This is a known slow-starting service

Intervene if:

  • Sync has been progressing for more than 2x your expected deployment time
  • Error logs show clear failures (image pull errors, resource conflicts)
  • Resource events indicate quota or permission issues
  • Other deployments are backing up behind this one

Wrapping Up

ArgoCD's "Progressing" state doesn't have to be a deployment killer. With the right debugging techniques and recovery strategies, you can quickly identify the root cause and get your applications back on track. The key is understanding that ArgoCD is usually stuck for a reason – it's trying to protect you from deploying broken configurations.

Remember: ArgoCD is conservative by design. It would rather wait and be safe than deploy something that might break your production environment. Most of the time, that "stuck" sync is ArgoCD doing its job. Your job is to figure out why it can't complete and give it the help it needs.

The debugging techniques and recovery steps I've outlined here have saved me countless hours of frustration. Keep them in your toolkit, and you'll find that those mysterious "Progressing" states become much less mysterious – and much less stressful.

Share:

Was this article helpful?

Majid Iqbal Nayyar
Majid Iqbal Nayyar

Data Infrastructure Engineer

Your data is only as good as the infrastructure it sits on. I specialize in PostgreSQL, Redis, database migrations, backup strategies, and making sure your data survives whatever chaos your application throws at it.

Related Articles

More in Platform Engineering

View all →

Discussion