Skip to content

fix: retry latest version lookup and add latest-fallback opt-out - #303

Open
Thomas Seljen Tvedt (thomastvedt) wants to merge 2 commits into
Azure:mainfrom
thomastvedt:fix/retry-latest-version-lookup
Open

fix: retry latest version lookup and add latest-fallback opt-out#303
Thomas Seljen Tvedt (thomastvedt) wants to merge 2 commits into
Azure:mainfrom
thomastvedt:fix/retry-latest-version-lookup

Conversation

@thomastvedt

@thomastvedt Thomas Seljen Tvedt (thomastvedt) commented Sep 10, 2026

Copy link
Copy Markdown

What happens today

When version is latest (the default), getLatestHelmVersion makes a single request to https://get.helm.sh/helm-latest-version. If that one request fails for any reason, the action logs a warning and installs the hard-coded stableHelmVersion (v3.18.4). The step stays green.

That URL now returns v4.3.0, so the fallback moves a job back an entire major version on a single transient network failure. The run then fails later on something that does not look related. In our case a deploy died on Error: unknown flag: --rollback-on-failure several steps after the silent downgrade, and it took a while to trace it back to this step.

The same file already takes the opposite position for the major.minor path. The comment on helmPatchExists says: "Any other status (403/405/429/5xx, ...) and genuine network errors are thrown, so transient failures, rate-limiting, or a host that disallows HEAD are never mistaken for a missing patch." Only the latest path guesses, and it guesses across a major.

This is the bug reported in #187 (closed after the reporter found the fallback documented in the README, with the unanswered request "It should at the very least be possible to opt out of the fallback"). The same symptom was reported in #136, #219, #221 and #226. #188 is about the constant going stale, which this PR does not change.

What this PR does

  1. Retries the lookup. fetchLatestHelmVersion makes up to 3 attempts with a 1 s, then 2 s wait between them. A non-2xx response is treated as a failure instead of installing the response body as a version. A single transient failure no longer decides the outcome.
  2. Stops falling back across a major by default. A new latest-fallback input controls what happens once the retries are exhausted. It defaults to 'false': the step fails with the underlying error. Setting it to 'true' restores today's behavior, installing stableHelmVersion with the same warning as before.

About that default

This is the one judgement call in the PR, so it is worth stating plainly rather than burying: it changes what happens in the failure path, and a workflow that would previously have gone green on a Helm 3 install will now fail instead.

The reasoning for 'false':

  • The retries make the fallback path rare. It is reached only when three attempts spread over three seconds all fail, which is a different situation from the single-request failure that reaches it today.
  • When it is reached, the outcome today is not "an older Helm". It is "a Helm from the wrong major, installed silently, in a job whose flags belong to the other major". Failing at this step names the problem; installing the wrong major hides it until something further down breaks.
  • A step that fails is re-runnable. A step that silently installed the wrong tool costs someone an afternoon.

If you would rather not change the default in a minor release, I am happy to flip it to 'true' here and leave 'false' for a future major, or to drop the input entirely and keep only the retries. The retry part stands on its own and is the piece that fixes the reported incidents. Say which you prefer and I will push the change.

Out of scope: changing stableHelmVersion to a Helm 4 default. That would change what v3 users get when the fallback applies and belongs with #188 and #241.

Changes

  • src/run.ts: fetchLatestHelmVersion with retries; getLatestHelmVersion(fallbackToDefault = false); run() reads latest-fallback.
  • src/run.test.ts: tests for retry-then-succeed, every attempt failing (throws), every attempt failing with the fallback enabled, and two run() cases for the input. The retry backoff runs under fake timers so the suite stays fast.
  • action.yml: latest-fallback input, default 'false'.
  • README.md: the note about the fallback describes the retries and the new default.

npm test (57 passing), npm run typecheck and npm run format-check pass locally. lib/ is not touched.

🤖 Generated with Claude Code

Resolving 'version: latest' made a single request to
https://get.helm.sh/helm-latest-version and, on any failure, silently
installed the hard-coded default version. Since 'latest' resolves to
Helm 4, that fallback moves a job back a whole major version while the
step stays green.

Retry the lookup a few times with a short backoff, treat non-2xx
responses as failures instead of installing the response body, and add
a 'latest-fallback' input so callers can make the step fail instead of
installing the default version. The default keeps the existing
behavior.
Make 'latest-fallback' default to 'false', so an exhausted lookup fails
the step with the underlying error instead of installing the built-in
default version, which can be a major behind what 'latest' resolves to.
Setting the input to 'true' restores the previous behavior.
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