File not found error during production distribution on case-sensitive filesystems
0 reputation · 29 Jul 2024, 17:07 UTC
0 reputation · 29 Jul 2024, 17:07 UTC
Ren'Py development environments on Windows often operate on case-insensitive filesystems, allowing assets to load regardless of whether the script matches the filename's casing. However, when distributing a production build to Linux or Android, the engine adheres to case-sensitive filesystem rules.
This discrepancy creates a scenario where a project functions perfectly during local testing but fails to locate assets once packed into .rpa archives or deployed to a target device. This is particularly problematic when assets are referenced inconsistently across different script files.
What is the recommended method for auditing all asset paths to ensure case consistency before the build process? Does Ren'Py provide a built-in validation tool to detect these mismatches prior to distribution?
Ren'Py does not include a built-in validation tool that audits asset paths for case-sensitivity mismatches. The Launcher's Lint Project command checks script syntax and reference validity on the current filesystem, but it runs on the developer's OS—so on Windows it will not surface case mismatches that later break on Linux or Android.
Windows filesystems (NTFS, FAT32) are case-insensitive by default. Ren'Py running on Windows will load bg_park.png even if the script references bg_Park.png. When the project is packed into .rpa archives or deployed to Linux/Android, the underlying filesystem becomes case-sensitive, and the engine can no longer resolve the mismatched path.
Write a small Python script (or an init python block in your project) that:
game/ directory with os.walk or pathlib.Path.rglob to build a set of actual filenames with exact casing..rpy file for quoted asset strings used in image, scene, show, play, sound, movie, background, cursor, and similar statements.# Example standalone audit script (run from project root)
import os, re, pathlib
GAME_DIR = pathlib.Path("game")
# 1. Collect actual files with exact case
actual = {p.relative_to(GAME_DIR).as_posix() for p in GAME_DIR.rglob("*") if p.is_file()}
# 2. Find asset references in .rpy files
asset_pattern = re.compile(r'"([^"]+\.(?:png|jpg|webp|ogg|mp3|wav|mp4|webm|ttf|otf))"')
mismatches = []
for rpy in GAME_DIR.rglob("*.rpy"):
text = rpy.read_text(encoding="utf-8")
for m in asset_pattern.finditer(text):
ref = m.group(1).replace("\\", "/")
if ref not in actual:
mismatches.append((rpy, m.start(), ref))
# 3. Report
if mismatches:
for f, pos, ref in mismatches:
line = f.read_text(encoding="utf-8")[:pos].count('\n') + 1
print(f"{f}:{line}: case mismatch → {ref}")
else:
print("All asset references match on-disk casing.")
Adopt a single casing convention—all lowercase is the most common—for both asset filenames and every script reference. Enforce it with a pre-commit hook or CI check that runs the audit script above.
The only definitive confirmation is running the packaged build on a case-sensitive filesystem. Options:
.rpa with unzip -l or 7z l to verify stored filenames match references exactly.If you already run CI on Linux, does the pipeline execute the built game (or at least the Ren'Py lint command) on that runner? That single fact changes whether you need a local audit script or can rely on CI to catch mismatches.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.