Skip to content

fix: recover gracefully from corrupt/empty mapImage.png on startup#518

Draft
dmccoystephenson wants to merge 3 commits into
mainfrom
fix/map-image-corrupt-file
Draft

fix: recover gracefully from corrupt/empty mapImage.png on startup#518
dmccoystephenson wants to merge 3 commits into
mainfrom
fix/map-image-corrupt-file

Conversation

@dmccoystephenson

Copy link
Copy Markdown
Member

Summary

  • In the web/WASM build (OPFS), a partially-written or zero-byte mapImage.png passes os.path.exists() but causes PIL to throw UnidentifiedImageError at startup, crashing the game before the first frame renders.
  • getExistingMapImage() now catches any image-open exception and falls back to createNewMapImage(), logging a warning so the bad file is detectable in logs.

Root cause

mapImageExists() only checks file presence, not validity. OPFS/IndexedDB can leave a zero-byte or partially-flushed file behind after an interrupted save, which PIL cannot parse.

Test plan

  • python3 -m pytest tests/ -q — all tests pass
  • python3 -m black --check src tests — no formatting violations
  • Load web build with a corrupted/empty mapImage.png in the save dir — game starts instead of throwing UnidentifiedImageError

🤖 Generated with Claude Code

dmccoystephenson and others added 3 commits July 6, 2026 14:39
In the web/WASM environment (OPFS), a partially-written or zero-byte
mapImage.png passes os.path.exists() but then causes PIL to throw
UnidentifiedImageError. Catch all image-open exceptions in
getExistingMapImage() and fall back to createNewMapImage() so the
game loads instead of crashing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without explicit cache headers, browsers serve stale game.zip after a
redeploy, masking fixes until the user hard-refreshes. Force revalidation
for all .zip and .js paths so a new container image is always picked up.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
build_zip.py now writes a SHA-256 of game.zip to web/game_version.txt.
game-worker.js fetches that file with cache:'no-store' and appends the
hash as ?v=<hash> to the zip URL. A new deploy changes the hash, changes
the URL, and forces every browser to download the new bundle — no hard
refresh or cache clearing needed.

serve.py applies no-store to game_version.txt and no-cache to .zip/.js.
Both generated files (game.zip, game_version.txt) added to .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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