fix(build): a romfs folder without the game's files is refused before the build #534
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8015c9a
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!534
Loading…
Reference in a new issue
No description provided.
Delete branch "jarynclouatre/Longshot:fix/romfs-without-game-files"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type: fix · Risk: low · Tested on: Linux x86-64 (game-free checks only) · Needs: none
Why
Issue #467: a romfs folder that held another tool's packed copy (an
index.jsonand one 25 GBromfs.bin) was accepted. The build ran for 15 minutes, filled 27 GB, and the game stopped at boot ("indirect call to an address with no function"), since its system files were not there.nx2/make_game.pyonly checks that the chosen romfs and exefs are folders (parse_argsfor--game,mainfor--romfswith--exefs), then links the romfs into the game folder as it is.How to reproduce
Seen on: Issue #467; OS, GPU and driver not recorded.
Settings and switches:
--game, or--romfswith--exefs, using folders.Steps: Choose a romfs folder holding another tool's packed copy, an
index.jsonand one 25 GBromfs.bin, and build.Expected: The folder is refused before the build, with a message to choose the extracted RomFS.
Actual: The folder was accepted; the build ran for 15 minutes, filled 27 GB, and the game stopped at boot ("indirect call to an address with no function") because its system files were missing.
What changed
The builder now checks that a chosen romfs folder holds the files it needs before making the game folder. A packed copy is refused with a message to extract it first.
nx2/make_game.py):check_romfs_folderlooks for what the build itself reads from the romfs,Pack/ZsDic.pack.zs(prompt_assets.py,shader_census.py) andSystem/Resource(prompt_assets.py's size table). It runs inmainbefore the game folder is made, for--gameand for--romfswith--exefs; not for--nup(which has its own "did not contain a romfs folder") or--update. A folder without them fails with "The romfs folder does not hold the game's files (no Pack/ZsDic.pack.zs): choose the extracted RomFS."; one holding aromfs.binalso says it is a packed copy to extract first. It looks throughlong_path, as the copy does, so a dump whose deepest paths pass 260 characters on Windows is still found. No file count or hash: a good dump with mods is not refused.tests/test_make_game_cache.py): the packed copy, an empty folder and a folder withPack/ZsDic.pack.zsbut noSystem/Resourceare each refused with their sentence, before the game folder exists and before the exefs is copied; a folder with both reaches the lift and is linked in; the check looks throughlong_path. The harness letsnx2/unpack.pythrough for a chosen exefs (its stand-in module is already unpacked), and the reparse case's source romfs gets the two stand-ins so it still reaches the check it tests.Measurements
Verdict: the new checks fail on main and pass here; the suite has no new failures.
this PR: fix/romfs-without-game-files @
0f83aaae(the suite runs below were on5101c7ae;0f83aaaechanges only the test's dictionary stand-in, which now starts as zstd, so a later check of the chosen folder's .zs files reads it as whole)Hardware: none used (game-free checks on a Linux x86-64 PC, Python 3.14, gcc 15.2)
Scene: none, the game was not run
Method: 2026-11-14.
python3 -I -B tests/run_all.py, two runs each, interleaved (main, PR, main, PR). The new checks also ran against main'snx2/make_game.py(LONGSHOT_CACHE_TEST_SOURCE, in a full checkout of main).How to reproduce: the commands above in a checkout of each commit
543846eb5101c7aetests/run_all.py(run 1, run 2)test_bake_portability.py,test_walk_key.pytests/test_make_game_cache.py, new refusal casetest_bake_portability.pyfails here for a missing Python module (zstandard).test_walk_key.py's fixture doesn't link on main (undefined reference to hos_oot_autoload_input).Flags and settings
None.
Testing
Tested: the game-free suite on a Linux PC, as in Measurements.
Not tested: a real dump or a real packed copy, the AppImage, and the launcher's folder picker (in its own repository); the message shows wherever make_game's error lines show.
Must be tested: None.
Risks
What could break: A romfs folder without
Pack/ZsDic.pack.zsorSystem/Resourceis now refused where it was built before; every supported dump has both, since the build reads them.Turning it off: Reverting the commit takes the check out.
Compatibility: Nothing changes for a game already built; a packed copy chosen as the romfs is refused with a message before the build starts.
Issues
Fixes #467
Checklist
Everyone
type(scope): description) of the status line's type.main.python -I -B tests/run_all.pypasses (any failure that also fails onmainis named).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
mainand passing here.tests/that reads changed source updated in this PR, not weakened.WIP: fix(build): a romfs folder without the game's files is refused before the buildto fix(build): a romfs folder without the game's files is refused before the build5101c7aeb10f83aaaeb4Reviewed exact head
0f83aaaeb4f48978765f516d4cf7692a22053e5d; no correctness issue found in the complete two-file diff.Independent Windows 11 build 26300 / Python 3.14.7 check:
tests/test_make_game_cache.pyruns 20 cases, OK with one existing platform-dependent skip. Running that same new fixture against unchanged main543846ebgives four errors: the helper is absent, and the packed/empty/incomplete folder cases reach the fixture's lift boundary instead of being refused. On the PR those folders exit before the output or extraction folders are created, while an authored valid layout reaches the lift boundary. All files in this check are authored stand-ins; no game build or actual dump was used.The guard runs before output-folder creation, uses the existing long-path helper, and checks two paths actually consumed by the prompt/shader readers. NUP and update handling retain their previous route. The added mocks support the new folder-input cases; existing cache/security assertions remain. This approves the bounded folder-layout validation change, not comprehensive dump integrity validation or a fresh full-suite/game build. The long-path routing case passes; no separate native >260-character fixture was run in this review.
This would also stop two boot crashes: issue #689 and a v3.0.0-rc.4 player's report both crash at boot with "write 0x100000000000, guest 0" because their romfs had no System folder. Removing only
System/HeapSize/Product.Nin_Ounce_NVN2.HeapDef.byml.zsfrom a whole romfs reproduces it (RTX 5080), so a dump that hasSystem/Resourcebut no heap definition still passes this check. Could you add the heap definition to the list (the game opensProduct.thenDefault.Nin_Ounce_NVN2.HeapDef.byml.zs), and run the check after a.nupis extracted too? Then this fixes #689 as well.