ArgoCD sync operations hang or fail when resource hooks (PreSync, PostSync, Sync, SyncFail) encounter errors, timeouts, or resource conflicts. Causes include Jobs getting deleted before completion, immutable field errors, hook timeout mismatches, or unfinished hook resources. Fix by adjusting ttlSecondsAfterFinished, using proper delete policies, implementing health checks, and debugging hook resource status.
ArgoCD hooks are Kubernetes resources (Jobs, Pods, etc.) annotated with argocd.argoproj.io/hook that run before, during, or after a sync operation. When a hook fails, times out, or becomes stuck in a pending state, the entire sync operation is blocked. This typically happens because hook resources are not completing successfully, ArgoCD cannot detect completion, or subsequent hook phases cannot proceed due to resource conflicts. Understanding hook lifecycle and deletion policies is critical to debugging sync failures.
Navigate to your Application > Sync Result tab to see hook execution status:
# Or query via CLI
kubectl get job -A | grep -E "presync|postsync|sync-hook"
kubectl describe job <hook-job-name> -n <namespace>Look for: Completed/Failed/Pending/Unknown states. Check job logs:
kubectl logs job/<hook-job-name> -n <namespace>Prevent Jobs from being deleted before ArgoCD detects completion:
apiVersion: batch/v1
kind: Job
metadata:
name: presync-migration
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceeded
spec:
ttlSecondsAfterFinished: 60 # Allow 60 seconds for detection
backoffLimit: 1
template:
spec:
containers:
- name: migrator
image: my-migration:latest
command: ["./migrate.sh"]
restartPolicy: NeverMinimum recommended: 60 seconds. Higher values if hook takes longer to complete.
Delete policies control when hook resources are cleaned up:
metadata:
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceededDelete policies:
- BeforeHookCreation: Delete resource before creating new one (prevents immutable field errors)
- HookSucceeded: Delete after hook succeeds
- HookFailed: Delete if hook fails
Recommended for Jobs: BeforeHookCreation,HookSucceeded. Do NOT use alone without one of the completion policies.
Ensure hook timing aligns with your workflow:
# Run before any resources sync
argocd.argoproj.io/hook: PreSync
# Run after main resources synced
argocd.argoproj.io/hook: PostSync
# Run during main sync (between PreSync and PostSync)
argocd.argoproj.io/hook: Sync
# Run only if sync fails
argocd.argoproj.io/hook: SyncFailCommon pattern: PreSync for schema migrations, Sync for main deployment, PostSync for tests/verification.
Verify the hook resource itself is healthy:
kubectl get job <job-name> -n <namespace> -o jsonpath="{.status}"
# Check pod logs for failures
kubectl get pods -l job-name=<job-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>
# Check for timeout issues
kubectl describe job <job-name> -n <namespace> | grep -i "timeout\|backoff"Ensure:
- Job completes successfully (Succeeded=1)
- Pod exits with code 0
- Active pods count reaches 0
- No backoff warnings
If hooks fail with "Field is immutable" errors:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
spec:
syncPolicy:
syncOptions:
- ServerSideApply=true
- ApplyOutOfSyncOnly=trueServerSideApply allows updating objects without recreating them. Combined with ApplyOutOfSyncOnly, prevents unnecessary hook re-runs.
Use sync waves to control hook execution order:
metadata:
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/sync-wave: "0" # Runs first
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceeded
---
metadata:
annotations:
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/sync-wave: "1" # Runs after wave 0Waves ensure hooks complete before dependent resources deploy. Default wave is 0.
Common pitfall: Jobs without ttlSecondsAfterFinished or with 0 value get cleaned up immediately, causing ArgoCD sync to get stuck in hook phase (Issue #21055). Always set reasonable ttl values. If using Helm charts with helm.sh/hook annotations, these are not automatically translated to ArgoCD hooks—you must explicitly annotate for ArgoCD. For critical hooks in production, use SyncFail hooks to handle hook failures gracefully. PostSync hooks getting stuck may indicate resource creation/deletion loops; use hook-delete-policy carefully. Rootless deployments or restrictive RBAC may prevent hook execution; verify service account permissions. See official ArgoCD resource hooks documentation for latest fixes and known issues.
Failed to connect to server: connection refused (HTTP/2)
How to fix "HTTP/2 connection refused" error in Kubernetes
missing request for cpu in container
How to fix "missing request for cpu in container" in Kubernetes HPA
error: invalid configuration
How to fix "error: invalid configuration" in Kubernetes
etcdserver: cluster ID mismatch
How to fix "etcdserver: cluster ID mismatch" in Kubernetes
running with swap on is not supported
How to fix "running with swap on is not supported" in kubeadm