How to fix ArgoCD hook failed in Kubernetes
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.
Quick fix
Fixes ArgoCD hook failed
# Or query via CLI
kubectl get job -A | grep -E "presync|postsync|sync-hook"
kubectl describe job <hook-job-name> -n <namespace>- Check hook resource status in ArgoCD UI
- Set proper ttlSecondsAfterFinished on hook Jobs
- Apply correct hook-delete-policy
- Use correct hook type for your use case
# Or query via CLIkubectl get job -A | grep -E "presync|postsync|sync-hook"kubectl describe job <hook-job-name> -n <namespace>ArgoCD hook failed
What this error means
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.
Typical symptoms
- Sync operation stuck in "Running" or "Waiting for hook completion" state
- ArgoCD UI shows hook resource failing or pending indefinitely
- PreSync/PostSync/Sync hooks not triggering at all
- Job resources deleted before hook completion can be detected
- Error: "Field is immutable" when hook Jobs are being re-synced
- Multiple sync attempts deleting and re-creating hook resources
- Hooks pass locally but fail in ArgoCD sync
Common causes
- Job has ttlSecondsAfterFinished=0 or very low value, deleted before ArgoCD detects completion
- Hook resource never reaches success state (Job/Pod fails or times out)
- Immutable field error in hook Jobs when re-synced (no BeforeHookCreation delete policy)
- Hook timeout too short relative to actual job duration
- Helm hooks (helm.sh/hook) not translated to ArgoCD hooks properly
- Missing or incorrect hook-delete-policy annotation
- Hook resources in different sync wave blocking later waves
- ArgoCD stuck hook bug where sync never completes despite resource success
How to fix "ArgoCD hook failed"
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.
Advanced notes
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.
Frequently asked questions
- What does "ArgoCD hook failed" mean?
- 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.
- How do I fix "ArgoCD hook failed"?
- 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.
- What causes "ArgoCD hook failed"?
- Job has ttlSecondsAfterFinished=0 or very low value, deleted before ArgoCD detects completion Hook resource never reaches success state (Job/Pod fails or times out) Immutable field error in hook Jobs when re-synced (no BeforeHookCreation delete policy)
- Is the "ArgoCD hook failed" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- ๐Kubernetes Official Documentation
- ๐
- ๐
- ๐
- ๐GitHub #21055: argoproj/argo-cd(GitHub)
- ๐GitHub #6880: argoproj/argo-cd(GitHub)