Skip to content

Make BepInEx/ValheimPlus updaters resilient to transient API failures (fixes #778) - #781

Merged
JustinTArthur merged 3 commits into
community-valheim-tools:mainfrom
dreeko:fix/issue-778-mod-updater-resilience
Oct 4, 2026
Merged

JustinTArthur merged 3 commits into
community-valheim-tools:mainfrom
dreeko:fix/issue-778-mod-updater-resilience

Conversation

@dreeko

@dreeko dreeko commented May 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #778. Issue reporter saw a transient HTTP 403 from Thunderstore's API on container restart, which permanently blocked the Valheim server from starting (workaround was disabling BEPINEX).

Thunderstore.io (BepInEx) and the GitHub releases API (ValheimPlus) both sit behind CDNs/WAFs that intermittently 403/429/5xx automated clients, especially on default curl User-Agent. The previous code did a single one-shot curl with no retry and no fallback, so any blip cascaded into a startup outage:

  1. bepinex-updater (or valheim-plus-updater) calls fatal and exits 1.
  2. check_mod in valheim-updater returns non-zero.
  3. update() bails out before write_restart_file.
  4. check_server_restart never sees a restart marker, so supervisorctl start valheim-server is never called.
  5. Server stays down until the next UPDATE_CRON tick succeeds.

This is asymmetric with the existing Steam-download path in update() (valheim-updater:51-58), which already falls back to a locally-cached valheim_server.x86_64 when Steam fails.

Changes

  • bepinex-updater / valheim-plus-updater: Add curl --retry 5 --retry-delay 5 --retry-all-errors --retry-max-time 90 and a stable User-Agent: valheim-server-docker to both API calls. --retry-all-errors requires curl >= 7.71 (trixie ships 8.x, so fine).
  • valheim-updater (check_mod): When the mod updater fails and $mod_install_path/valheim_server.x86_64 already exists from a previous successful merge, log a warning and return 0 instead of blocking the boot. The next UPDATE_CRON tick still gets a chance to apply updates.

The "mod disabled but previously installed" refresh branch in check_mod is intentionally left alone — it's an opportunistic refresh and isn't load-bearing for server startup.

Fixes community-valheim-tools#778

Thunderstore.io (BepInEx) and GitHub (ValheimPlus) APIs intermittently
return 403/5xx (Cloudflare bot management, rate limits, brief outages).
The previous code did a single curl with no retry and no fallback, so
a transient blip would:
  1. fail bepinex-updater / valheim-plus-updater with `fatal`
  2. cause check_mod in valheim-updater to return non-zero
  3. cause update() to bail out before write_restart_file
  4. leave valheim-server unstarted until the next UPDATE_CRON tick

Three changes:

* Add curl --retry 5 --retry-delay 5 --retry-all-errors
  --retry-max-time 90 to both updaters, plus a stable User-Agent
  ("valheim-server-docker") so CDNs don't lump us in with default-curl
  traffic.

* Fall back to the existing mod installation in check_mod when the
  updater fails but $mod_install_path/valheim_server.x86_64 is already
  present from a previous successful merge. Mirrors the existing Steam
  download fallback in update() (valheim-updater:51-58). This is the
  fix that actually unsticks cold starts after a transient API blip.

* Leave the "mod disabled but previously installed" refresh path
  unchanged - it's opportunistic and not load-bearing for boot.
@dreeko
dreeko force-pushed the fix/issue-778-mod-updater-resilience branch from 4f705bc to 11ee8ed Compare May 14, 2026 03:03
@dreeko
dreeko marked this pull request as ready for review May 14, 2026 03:04
Both updaters' API calls and download_mod now go through fetch_url, which
retries the transient refusals from Thunderstore's and GitHub's CDNs (community-valheim-tools#778)
and caps each attempt with --connect-timeout/--max-time so one stalled
transfer can't hang the updater. API calls use a 30s cap.

download_mod needed this as well, since the archive download from
thunderstore.io sits behind the same Cloudflare as its API. It now
downloads to a temp file and only replaces the cached archive once
complete, so a failed download no longer leaves a partial archive for
check_merge to extract when a Valheim update requests a merge.

@JustinTArthur JustinTArthur left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. I'm moving it to a common function to cut down on repetition, then will merge.

@JustinTArthur
JustinTArthur merged commit ee2bcf8 into community-valheim-tools:main Oct 4, 2026
8 checks passed
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.

BepInEx updater not working - Error code 403 - server not starting

3 participants