Palworld: manager disables the image's updater (UPDATE_ON_BOOT=false) but has no working replacement update path. Existing servers can't update
Environment:
Palisade: ghcr.io/shakes63/palisade:latest
Host: Unraid
Game: Palworld, image thijsvanloef/palworld-server-docker:latest
Symptom: existing instance stuck on an old build (v1.0.0.100427) while the current Steam build was v1.0.1.100619. Install/Update button does nothing; Stop/Start and Restart do not trigger an update.
Summary:
Palisade intentionally turns off the base image's own update loop but does not run a working update path of its own for Palworld. The result is that an existing instance can never be moved to a newer game build through the manager. A fresh instance installs current (because first-boot install always runs), which masks the problem until the next game patch.
Root cause (traced in source):
In apps/api/src/servers/runtime-spec.ts, buildPalworldSpec() hardcodes into the container env (lines ~479-480):
ts// The manager owns updates/backups/restarts — turn off the image's own loops.
// (A fresh instance still installs on first boot regardless of UPDATE_ON_BOOT.)
UPDATE_ON_BOOT=false,
BACKUP_ENABLED=false,
AUTO_REBOOT_ENABLED=false,
The intent is correct. The manager takes ownership of updates instead of the image. The gap is that the manager side of that contract does not run for Palworld. The image's UPDATE_ON_BOOT path (which runs the update on boot) is off, and nothing in Palisade runs an equivalent update afterward. This is unconditional; there's no per-instance flag or env override exposed to change it.
Corroborating evidence from the DB:
In the Server row for the Palworld instance (db.sqlite):
configJson holds only gameplay settings (rates, difficulty, PvP, etc.) — none of the operational env vars, so there's no user-facing way to set UPDATE_ON_BOOT.
installedBuildId is empty - the manager isn't tracking the installed build at all.
updateAvailable stays 0 - with no known installed build to compare against, update detection can't fire.
This matches the observed behavior: the Install/Update button has nothing to act on. On boot the container logs Checking for available container updates -> The container is up to date!, but that's an image-freshness check, not a game-version check, so it's misleading.
Workaround that works (and one that doesn't):
steamcmd was unreliable in this environment. Running app_update 2394010 validate repeatedly failed with:
Update state (0x0) : Timed out waiting for update to start, bailing.
Error! App '2394010' state is 0x6 after update job.
This persisted across retries and with a dedicated persistent Steam home dir.
DepotDownloader (which the image ships and exposes via USE_DEPOT_DOWNLOADER=true) worked reliably. Running the image's own entrypoint against the instance's bind-mounted data dir, with the server stopped, pulled the full ~4.7 GB update and brought the instance to v1.0.1.100619:
bashdocker run --rm -it
-e PUID=99 -e PGID=100
-e USE_DEPOT_DOWNLOADER=true
-e UPDATE_ON_BOOT=true
-e RCON_ENABLED=false
-e BACKUP_ENABLED=false
-v /host/path/to/instances/:/palworld
thijsvanloef/palworld-server-docker:latest
Critical prerequisite: the managed server must be fully stopped first. If it's running, the update fails with:
Text file busy : '/palworld/Pal/Binaries/Linux/PalServer-Linux-Shipping' because the binary is in use. Stopping via RCON isn't sufficient. The manager restarts the container afterward; the instance has to be stopped through the manager itself so it stays down during the update.
Suggested fix:
Wire the manager's Install/Update action (and ideally the stop/start path) to run an update against the instance before launch, then populate installedBuildId from the result so updateAvailable detection can work. Given the steamcmd timeouts seen here, DepotDownloader appears to be the more reliable engine to drive. The image already supports it via USE_DEPOT_DOWNLOADER=true. This preserves the "manager owns updates" design intent from runtime-spec.ts while actually delivering the update path.
As a quicker interim option, exposing per-server env overrides (see #11) would let users set UPDATE_ON_BOOT=true themselves as a stopgap.
Palworld: manager disables the image's updater (UPDATE_ON_BOOT=false) but has no working replacement update path. Existing servers can't update
Environment:
Palisade: ghcr.io/shakes63/palisade:latest
Host: Unraid
Game: Palworld, image thijsvanloef/palworld-server-docker:latest
Symptom: existing instance stuck on an old build (v1.0.0.100427) while the current Steam build was v1.0.1.100619. Install/Update button does nothing; Stop/Start and Restart do not trigger an update.
Summary:
Palisade intentionally turns off the base image's own update loop but does not run a working update path of its own for Palworld. The result is that an existing instance can never be moved to a newer game build through the manager. A fresh instance installs current (because first-boot install always runs), which masks the problem until the next game patch.
Root cause (traced in source):
In apps/api/src/servers/runtime-spec.ts, buildPalworldSpec() hardcodes into the container env (lines ~479-480):
ts// The manager owns updates/backups/restarts — turn off the image's own loops.
// (A fresh instance still installs on first boot regardless of UPDATE_ON_BOOT.)
UPDATE_ON_BOOT=false,BACKUP_ENABLED=false,AUTO_REBOOT_ENABLED=false,The intent is correct. The manager takes ownership of updates instead of the image. The gap is that the manager side of that contract does not run for Palworld. The image's UPDATE_ON_BOOT path (which runs the update on boot) is off, and nothing in Palisade runs an equivalent update afterward. This is unconditional; there's no per-instance flag or env override exposed to change it.
Corroborating evidence from the DB:
In the Server row for the Palworld instance (db.sqlite):
configJson holds only gameplay settings (rates, difficulty, PvP, etc.) — none of the operational env vars, so there's no user-facing way to set UPDATE_ON_BOOT.
installedBuildId is empty - the manager isn't tracking the installed build at all.
updateAvailable stays 0 - with no known installed build to compare against, update detection can't fire.
This matches the observed behavior: the Install/Update button has nothing to act on. On boot the container logs Checking for available container updates -> The container is up to date!, but that's an image-freshness check, not a game-version check, so it's misleading.
Workaround that works (and one that doesn't):
steamcmd was unreliable in this environment. Running app_update 2394010 validate repeatedly failed with:
Update state (0x0) : Timed out waiting for update to start, bailing.
Error! App '2394010' state is 0x6 after update job.
This persisted across retries and with a dedicated persistent Steam home dir.
DepotDownloader (which the image ships and exposes via USE_DEPOT_DOWNLOADER=true) worked reliably. Running the image's own entrypoint against the instance's bind-mounted data dir, with the server stopped, pulled the full ~4.7 GB update and brought the instance to v1.0.1.100619:
bashdocker run --rm -it
-e PUID=99 -e PGID=100
-e USE_DEPOT_DOWNLOADER=true
-e UPDATE_ON_BOOT=true
-e RCON_ENABLED=false
-e BACKUP_ENABLED=false
-v /host/path/to/instances/:/palworld
thijsvanloef/palworld-server-docker:latest
Critical prerequisite: the managed server must be fully stopped first. If it's running, the update fails with:
Text file busy : '/palworld/Pal/Binaries/Linux/PalServer-Linux-Shipping' because the binary is in use. Stopping via RCON isn't sufficient. The manager restarts the container afterward; the instance has to be stopped through the manager itself so it stays down during the update.
Suggested fix:
Wire the manager's Install/Update action (and ideally the stop/start path) to run an update against the instance before launch, then populate installedBuildId from the result so updateAvailable detection can work. Given the steamcmd timeouts seen here, DepotDownloader appears to be the more reliable engine to drive. The image already supports it via USE_DEPOT_DOWNLOADER=true. This preserves the "manager owns updates" design intent from runtime-spec.ts while actually delivering the update path.
As a quicker interim option, exposing per-server env overrides (see #11) would let users set UPDATE_ON_BOOT=true themselves as a stopgap.