Skip to content

Managed status updates on principal can clear a pending sync operation before application controller observes it #841

Description

@drewbailey

Summary

In managed mode, a principal-initiated sync request can be cleared by an incoming managed-agent status update before the ArgoCD application-controller observes the pending .operation.

The principal UpdateStatus() path previously copied incoming.Operation from the agent status payload directly onto the principal application. Managed-agent status updates often arrive with incoming.Operation == nil, especially immediately after application creation or early reconcile activity. If such a status update lands after the principal sets .operation but before the application-controller acts on it, the sync request is erased.

Impact

  • Newly created or recently updated managed applications can remain OutOfSync / Missing on the principal.
  • The sync operation appears to have been requested, but never starts.
  • Principal and agent may both end up with no .operation or .status.operationState, despite the deploy flow having requested a sync.

Environment

  • Managed mode
  • Principal initiates sync by setting .operation on Application
  • Agent emits early status updates during create/reconcile
  • Principal applies managed status updates via UpdateStatus()

Reproduction

  1. Create or update an ApplicationSet targeting managed agents.
  2. Principal creates the managed Application.
  3. Deploy flow or automation sets .operation on the principal application to trigger sync.
  4. Before ArgoCD application-controller on the principal processes that operation, the agent emits a status update for the same app.
  5. Principal handles that managed status update and copies incoming.Operation == nil over the existing pending operation.
  6. ArgoCD application-controller never sees a persistent sync request.

Expected Behavior

  • Once the principal sets a sync operation, a nil-operation status update from the agent should not clear it.
  • Pending sync intent should remain until:
    • the agent reports an updated operation payload, or
    • ArgoCD application-controller advances the operation state.

Actual Behavior

  • Principal application briefly gets .operation set.
  • A managed status update arrives from the agent with incoming.Operation == nil.
  • Principal UpdateStatus() clears the existing .operation.
  • The sync operation never starts.
  • Principal and agent can both end up with:
    • no .operation
    • no .status.operationState
    • app still OutOfSync / Missing

Evidence / Symptoms

Typical symptoms observed:

  • deploy flow requested sync
  • principal app later has no .operation
  • principal argocd-application-controller logs show no sync start for the affected app
  • agent status traffic appears immediately after create
  • app remains unsynced until another change re-triggers progress

Suspected Root Cause

In principal managed-mode UpdateStatus(), the code used to do:

  • existing.Operation = incoming.Operation
  • patch target Operation: incoming.Operation

When incoming.Operation == nil, that unconditionally removed any existing pending operation from the principal application.

This makes managed status updates race with sync initiation.

Relevant Code

  • internal/manager/application/application.go
    • principal UpdateStatus() path
  • Managed status updates often omit .operation
  • Principal sync initiation relies on .operation remaining present long enough for ArgoCD application-controller to act on it

Why This Is Separate From #840

This issue is about the principal clearing .operation after receiving a managed status update.

A separate issue exists where sync-carrying SpecUpdate events can be coalesced away before reaching the agent.

Proposed Fix

Preserve an existing operation when the incoming managed status update has incoming.Operation == nil.

reuse the same helper logic already used elsewhere for operation preservation:

  • preserve existing operation if incoming operation is nil
  • continue to honor explicit incoming operation updates
  • keep terminating-operation behavior intact

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions