Skip to content

fix(statewrite): retry an empty or errored manifest re-fetch instead of parsing it - #542

Merged
joshua-temple merged 1 commit into
mainfrom
fix/statewrite-refetch-guard
Jul 9, 2026
Merged

joshua-temple merged 1 commit into
mainfrom
fix/statewrite-refetch-guard

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Problem

On a rejected optimistic state write, CommitWithRetry re-fetches the current manifest and re-applies. The Contents API client swallows a transient GET failure and returns empty content, and that empty content was passed straight to the mutation, which parsed it and hard-failed the entire write with manifest file missing required 'ci' key at top level - even though the committed manifest was intact. Observed live on a fleet promote finalize; the committed manifest was verified clean, so the bad parse was on a transient empty re-fetch inside the write.

Fix

Treat an errored or empty/whitespace-only re-fetch as a retryable condition, like a 409: back off and retry within the existing bounded loop rather than parsing it. On exhaustion by a persistent empty/errored re-fetch, return a distinct non-parse error rather than a spurious missing-key error. Happy path, conflict-merge behavior, and single-component behavior unchanged. The git-based WithReapply re-apply path already fails closed on a bad fetch (reads the manifest only after a successful reset), so it needs no change.

Verification

Red-before/green-after tests: a write whose first re-fetch returns empty (and separately, errors) retries and succeeds; a persistently-empty re-fetch exhausts with a non-parse error and zero PUTs (no spurious missing-key); and a guard test that a genuinely invalid non-empty manifest still errors immediately (real invalidity not masked). go build, go test ./... (2690), -race, golangci-lint all clean.

…of parsing it

On a rejected optimistic write, CommitWithRetry re-fetches the current manifest and re-applies. The Contents API client swallows a transient GET failure and returns empty content, and that empty content was passed straight to the mutation, which parsed it and hard-failed the whole write with 'manifest file missing required ci key at top level' even though the committed manifest was intact. Treat an errored or empty re-fetch as a retryable condition, like a 409: back off and retry within the existing bounded loop rather than parsing it, and on exhaustion return a distinct non-parse error rather than a spurious missing-key error. The happy path, the conflict-merge behavior, and single-component behavior are unchanged. The git-based re-apply path already fails closed on a bad fetch and reads the manifest only after a successful reset, so it needs no change.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
@joshua-temple
joshua-temple merged commit 3ed14b6 into main Jul 9, 2026
20 checks passed
@joshua-temple
joshua-temple deleted the fix/statewrite-refetch-guard branch July 9, 2026 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant