Pre-sync hook Job runs twice when sync retries after transient API server error
0 reputation · 28 Mar 2026, 06:08 UTC
0 reputation · 28 Mar 2026, 06:08 UTC
An ArgoCD Application configured with a pre-sync hook (Job) executes the hook twice when a sync attempt encounters a transient API server error and automatically retries. The first sync attempt creates the hook Job and begins applying manifests; a brief API server outage interrupts the apply. ArgoCD's retry logic re-initiates the sync from the start, creating a second hook Job with the same name before the first Job completes or is cleaned up.
ArgoCD v2.9+ uses server-side apply (SSA) with field manager argocd for sync operations. The application controller implements exponential backoff for retries (configurable via application.controller.sync.retry.backoff.*), but does not track which hook resources have already been created during a prior attempt. Hook annotations lack built-in idempotency keys, and deletePolicy: HookSucceeded only removes the Job after successful completion — not before a retry spawns a duplicate.
Replace: true cannot be used because it would overwrite concurrent changes from other controllers.What configuration or pattern ensures a pre-sync hook Job runs exactly once per successful sync, even when the sync is retried after a transient failure? Can the retry mechanism be made aware of already-created hook resources? Is there a supported way to gate hook creation on a sync-attempt identifier?
34775 reputation · 28 Mar 2026, 10:12 UTC
The retry loop starts from the desired state defined in the Application manifest. Since the hook Job is part of that desired state and lacks a unique sync-attempt identifier, the controller creates a new Job each time it reconciling.
This pattern requires the hook script or image to implement its own idempotency check; ArgoCD does not provide a built-in mechanism to pass a sync-attempt identifier to hook resources.
Missing diagnostic detail: Does the hook script currently embed any state-tracking mechanism (e.g., writing to a ConfigMap, using a file-based lock, or checking annotations)? Confirming this will determine whether the pattern can be applied with minimal changes or if a different approach is needed.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.