Skip to content

Auto-sync skipped for multi-source apps whose path source also sets ref (regression from #25531, 3.4.0) #30558

Open

Description

@schmitz-chris

Checklist:

  • I've searched in the docs and FAQ for my answer: https://bit.ly/argocd-faq.
  • I've included steps to reproduce the bug.
  • I've pasted the output of argocd version.

Describe the bug

If every source of a multi-source Application sets ref, including the source that has path and renders the manifests, Argo CD 3.4 no longer auto-syncs new commits. The app turns OutOfSync and stays there until it is synced manually. selfHeal is not enabled. No manifest-generate-paths annotation is set.

A source with both path and ref is documented and supported (multiple_sources.md, v3.4.12, L81-L89):

If the path field is set in the $values source, Argo CD will attempt to generate resources from the git repository at that URL. If the path field is not set, Argo CD will use the repository solely as a source of value files.

Even when the ref field is configured with the path field, $value still represents the root of sources with the ref field. Consequently, valueFiles must be specified as relative paths from the root of sources.

We use this pattern for app-of-apps Applications whose chart reads value files from its own repository. These apps were auto-synced on 3.3.6; after upgrading to 3.4.12, every new commit has to be synced by hand.

Root cause

ApplicationSource.IsRef() returns Ref != "", so a source with path + ref counts as a ref source.

That assumption holds for a ref source that only provides value files. It does not hold for a ref source that also renders manifests. When every source sets ref, no source evaluates changes, so revisionsMayHaveChanges stays false. autoSync passes it to alreadyAttemptedSync as newRevisionHasChanges. With false, the function skips the revision comparison and only compares spec.sources with status.operationState.syncResult.sources (v3.4.12 controller/appcontroller.go L2486-L2505). The sources have not changed, so the sync counts as already attempted and is skipped (L2398-L2400). alreadyAttemptedSync is identical in 3.3.6, 3.4.12 and 3.5.6.

To Reproduce

Verified on 3.4.12 with a single Git repository and branch:

repro/sre-2567/chart/Chart.yaml
repro/sre-2567/chart/templates/configmap.yaml
repro/sre-2567/base-values.yaml      # base: from-chart-repo
repro/sre-2567/values.yaml           # counter: "1"
# Chart.yaml
apiVersion: v2
name: repro
version: 0.1.0
---
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}
data:
  base: {{ .Values.base | quote }}
  counter: {{ .Values.counter | quote }}

Two Applications that differ only in where ref: chartrepo is set:

# Affected: the path source also sets `ref`
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: sre-2567-path-and-ref
  namespace: argocd
spec:
  project: default
  destination: {server: https://kubernetes.default.svc, namespace: sre-2567-repro}
  syncPolicy:
    automated: {enabled: true}
    syncOptions: [CreateNamespace=true]
  sources:
  - repoURL: <repo>
    targetRevision: <branch>
    path: repro/sre-2567/chart
    ref: chartrepo
    helm:
      releaseName: path-and-ref
      valueFiles:
      - $chartrepo/repro/sre-2567/base-values.yaml
      - $values/repro/sre-2567/values.yaml
  - repoURL: <repo>
    targetRevision: <branch>
    ref: values
---
# Control: `ref: chartrepo` moved to a separate ref-only source
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: sre-2567-split-ref
  namespace: argocd
spec:
  project: default
  destination: {server: https://kubernetes.default.svc, namespace: sre-2567-repro}
  syncPolicy:
    automated: {enabled: true}
    syncOptions: [CreateNamespace=true]
  sources:
  - repoURL: <repo>
    targetRevision: <branch>
    path: repro/sre-2567/chart
    helm:
      releaseName: split-ref
      valueFiles:
      - $chartrepo/repro/sre-2567/base-values.yaml
      - $values/repro/sre-2567/values.yaml
  - repoURL: <repo>
    targetRevision: <branch>
    ref: values
  - repoURL: <repo>
    targetRevision: <branch>
    ref: chartrepo
  1. Apply both Applications. Both auto-sync the initial commit (cc4687ad) and both ConfigMaps show counter: "1".

  2. Commit counter: "2" to repro/sre-2567/values.yaml (8e4836e2) and push.

  3. Result after 6 minutes and three reconciliations (timeout.reconciliation: 120s):

    Application sync.status desired revisions last synced revisions ConfigMap counter
    sre-2567-path-and-ref OutOfSync 8e4836e2, 8e4836e2 cc4687ad, cc4687ad 1
    sre-2567-split-ref Synced 8e4836e2 (x3) 8e4836e2 (x3) 2

    For sre-2567-path-and-ref, spec.sources equals status.operationState.syncResult.sources, and the last operation was the initial automated sync.

Because both sources point to the same repository and branch, the revision of the path source also changed in this test. The app is skipped anyway, so the bug is not limited to value-file changes.

Expected behavior

A source with path is rendered, so it should be evaluated for changes like any non-ref source, whether or not it also sets ref. sre-2567-path-and-ref should auto-sync 8e4836e2 the same way sre-2567-split-ref does, as it did on 3.3.x.

One possible fix is to apply the ref-source short-circuit only to pure value-file sources, for example source.IsRef() && source.Path == "".

Version

$ argocd version
argocd: v3.5.4+d6d5b24.dirty
  BuildDate: 2026-10-06T23:03:39Z
  GitCommit: d6d5b248ce00e1a2c512068002a93d3319767087
  GitTreeState: dirty
  GitTag: v3.5.4
  GoVersion: go1.27.1
  Compiler: gc
  Platform: darwin/arm64
argocd-server: v3.4.12

Logs

Application controller, same reconcile window:

time="2026-10-28T16:44:03Z" level=info msg="Skipping auto-sync: most recent sync already to [8e4836e212c3e190d69317fb3db2db6fad5acff7 8e4836e212c3e190d69317fb3db2db6fad5acff7]" app-namespace=argocd application=sre-2567-path-and-ref project=default
time="2026-10-28T16:44:04Z" level=info msg="Initiated automated sync to '8e4836e212c3e190d69317fb3db2db6fad5acff7, 8e4836e212c3e190d69317fb3db2db6fad5acff7, 8e4836e212c3e190d69317fb3db2db6fad5acff7'" app-namespace=argocd application=sre-2567-split-ref project=default
time="2026-10-28T16:46:34Z" level=info msg="Skipping auto-sync: most recent sync already to [8e4836e212c3e190d69317fb3db2db6fad5acff7 8e4836e212c3e190d69317fb3db2db6fad5acff7]" app-namespace=argocd application=sre-2567-path-and-ref project=default
time="2026-10-28T16:48:49Z" level=info msg="Skipping auto-sync: most recent sync already to [8e4836e212c3e190d69317fb3db2db6fad5acff7 8e4836e212c3e190d69317fb3db2db6fad5acff7]" app-namespace=argocd application=sre-2567-path-and-ref project=default

The message prints the desired revisions. The last sync was to cc4687ad, so the wording "most recent sync already to" is misleading in this case.

Workaround

Do not set ref on a source that has path. Add a separate ref-only source with the same repoURL and targetRevision, as in sre-2567-split-ref.

Activity

  1. Cindia-blue commented on Oct 28, 2026

    @Cindia-blue

    I'd like to work on this regression. I will first reproduce it with a focused controller regression test, then check that sources which both render manifests and declare a ref are evaluated for revision changes, while keeping pure values-only sources and manifest-generate-paths behavior intact.

    I found no linked implementation or existing claim in the issue timeline. Please let me know if anyone is already working on this, or if maintainers prefer a different scope. I will validate the local change and wait for maintainer scope confirmation before opening a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions