Skip to content

Three Repository resources never retry after an async update failure, so a fixed root cause cannot reach them #137

Description

@devantler

🤖 Generated by the Agentic Engineer

Evidence

#112 restored the repository write path (#136, merged 2026-08-06T01:37:50Z, artifact 1.22.1). Every resource that attempted an update afterwards succeeded:

Repository LastAsyncOperation after the fix
aws Success 2026-08-06T01:39:11Z
doggy-countdown Success 01:39:09Z
kyverno-policies Success 01:39:11Z
provider-upjet-unifi Success 01:39:10Z

Three did not, and still report ReconcileError with the old 422 message:

Repository last update attempt age at 2026-08-06
agent-skills 2026-07-20T00:32:52Z 17 days
platform-tenant-template 2026-08-02T18:54:05Z 3 days
agent-plugins 2026-08-03T19:45:36Z 2 days

Problem

The Synced message on these three is the cached result of that old attempt, not a fresh rejection — the underlying cause it names was fixed and demonstrably no longer rejects anyone else. They are not being rejected; they are not trying.

That matters beyond these three repositories: it means a resource can enter a state where fixing the root cause is not enough to recover it, and the stale condition message actively misleads whoever looks — it points at a cause that is already resolved. Any future repository-settings failure can strand a resource the same way.

⚠️ Synced.lastTransitionTime is rewritten roughly every 60s whether or not anything happened, so it cannot be used to tell a fresh failure from a stale one. Use LastAsyncOperation.lastTransitionTime, which only moves when an operation actually completes.

Observation worth checking first

The three carry only the crossplane.io/external-name annotation. Healed resources such as kyverno-policies also carry crossplane.io/external-create-pending, crossplane.io/external-create-succeeded and crossplane.io/external-create-failed. Whether that is the cause or a side effect of the same history is unverified — it is the first thing to test, not a conclusion.

Suggested approach

  • Establish why no reconcile issues an update: a stuck async-operation record, an exponential backoff that has grown unbounded, or the resource being considered up to date while the condition says otherwise.
  • Prefer a fix that recovers automatically. A manual nudge (annotation bump, provider restart) may confirm the diagnosis, but a resource that cannot self-recover from a transient provider error is the actual defect.
  • Establish whether a bounded retry or a staleness check on LastAsyncOperation belongs in the repository-update contract, so a wedged resource is visible rather than silently frozen behind a stale message.

Acceptance criteria

  • All 20 Repository resources report ReconcileSuccess.
  • The mechanism that stopped the three from retrying is identified and recorded here.
  • A wedged resource is either recovered automatically or surfaced as a distinct signal, rather than presenting a stale message naming an already-fixed cause.

Blocks #112, which stays open until 20/20 is observed.

Evidence gathered live against admin@prod; no cluster mutation was performed, deliberately, so the stuck state remains available for diagnosis.

Activity

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

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions