Builder: a dump with a 5.5 GB zeroed stretch (11,935 Tex files) builds with stand-ins and the game crashes at boot; one damaged file passes the header check and is used as a stand-in source (v2.0.14) #2005
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot#2005
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Hookshot version
v2.0.14 (hookshot v2.0.14, source 3a9998c3; Hookshot Builder v2.0.14, Windows app, .nup, DLSS on)
What kind of problem
Crash, freeze or black screen
What happened
Pressing Play gives a black window for about six seconds, then the game closes. No frame is ever drawn. Every run crashes at the same place:
Guest code at
0x80942b3cloads a resource's dictionary pointer (ldr x0, [x1, #0x98]), gets NULL, and calls the routine at0x80942c60with the key"name"(x8 points at the string, x21 = 4); that routine walks 16-byte trie nodes and looks likenn::util::ResDic::FindIndex. It dereferences the null dictionary and faults at guest address 0x8. So a resource that the scene loader expects to carry a name dictionary has none.This is not a Hookshot bug as such: the dump is damaged. But the Builder turned a dump that cannot boot into a finished build, and its repair step copied a corrupt file over another one. Details below, then three suggestions.
The dump
.nupof 25,622,267,860 bytes (it sits in a Fritchii v5.6 folder, which I believe produced it), two titles (base0400486024dec000v65536 and update0400486024dec800v131072) sharing their extents. The Builder's own check:23,870 bad records = the same 11,935 files in each title. All of them are in
romfs/Tex(57.7% of its 20,667 files). Reading the.nupdirectly: bytes 17,081,511,906 through 22,583,759,606 are zero, one unbroken stretch of 5.50 GB (21.5% of the file; 200 of 200 64 KB samples across it are zero). The stretch begins 56,898 bytes intoTex/HillWall_Graveyard_Assets_A_RAH.bntx.zsand ends 35.7% intoTex/RBake_Scene_SacredForestMeadow_Child_G_1_1_d1_shgi0_un3.bntx.zs; every member stored between those two is entirely zero. This is a different failure from the known 23.3 GB dump with three zeroed textures (#1308, #1002): it looks like a dumper or copy failure over one contiguous region, and I will re-dump. I'm reporting it because of what the Builder and the game did with it.What the Builder did
nx2/make_game.py→stand_in_damaged_files→nup.stand_in_damagedfound the 11,934 files whose first four bytes are not the zstd magic and replaced 11,857 of them with a look-alike neighbour (same suffix, longest common name prefix, nearest size); for 77 it found "nothing similar" and left them zero-filled (every candidate with the same suffix was damaged too). It prints the "Your game dump is incomplete: 11934 game files in it are damaged..." notice with one line per file; I can't say how much of that the Builder window surfaced, only that the build finished and the launcher offered Play. Checked on disk today: 11,858 of the 11,935 damaged paths start with the zstd magic (the 11,857 stand-ins plus the file below), 77 are all zeros.The 11,935th damaged file is the interesting one.
Tex/HillWall_Graveyard_Assets_A_RAH.bntx.zs(149,660 bytes) kept its first 56,898 bytes, so it starts with the zstd magic and a plausible frame header (content size 180,336), but the rest is zeros:904af137e2eb685e1bf95e599ab402ce9e51eb14647e67bafd1d857218ab2bfc, actualdbddee9495ec44ea0f1121bc0f20154cbef11f9827eccf4d61f77c48c9569120zstandard.ZstdDecompressor().decompress()→ "Data corruption detected"damaged_game_filesonly looks at the first four bytes, so this file was not treated as damaged. Worse,stand_in_forthen chose it as the stand-in forTex/Ice_LakeHrl_IceBlocks_A_01_RAH.bntx.zs(149,597 bytes, zero from byte 0 in the dump): everyIce_*_RAHcandidate was damaged, so the common-prefix score was 0 for all remaining candidates and the nearest size won. The on-diskIce_LakeHrl_IceBlocks_A_01_RAH.bntx.zsis now byte-identical to the corruptHillWallfile. So the repair step propagated a corrupt file. The header-only check is unchanged onmainas of today (nx2/nup.py,damaged_game_files/stand_in_for).What the game did
A
--tracerun shows 568fs: OpenFile(content:/Tex/...)calls before the crash (510 distinct textures); 234 of those calls (191 distinct files) are stand-ins. The crash follows on theSceneLowPrioritythread right aftertera::FileResourceMgris started, in the null-dictionary lookup above.To check that the stand-ins are the cause and not a bystander, I renamed the 11,858 damaged files that have a zstd header away (the 11,857 stand-ins and the
HillWallfile, so the game saw them as missing, like the 77 zero files) and ran again. It crashed earlier, at 3.6 s, on the main thread:Tex/MaterialAlb.bntx.zs(49,797,833 bytes) is one of the zeroed files and is opened at boot byARes Loading 1. The files were restored afterwards (11,858 of 11,858). Either way this dump cannot reach the first frame, with or without the stand-ins.Ruled out: the exefs build id is the supported
e0f3ccfa...; v2.0.14 is the newest release;HOS_VCORES=0andRX_VK_NO_MESH=1change nothing; no other issue has this crash signature (0x80942b5c,+0xe2bed37). Related: #1002, #1308, #1373, #1885 and #626 cover the three-file 23.3 GB case and the check's performance; none covers thousands of damaged members or a damaged member that passes the header check.Suggestions
Tex) the game cannot boot, so the build only buys an hour of compiling and a confusing crash. A threshold (a few dozen files, or any damaged file in the boot set) could fail the build with the count and the--verifycommand, or the launcher could show the count before Play. Writing the count intohookshot_log.txtat start (e.g.romfs: 11935 stand-in textures (incomplete dump)) would also let anyone triage a report like this from the log alone.--verifycompares them). A mismatching member should count as damaged even when its zstd magic survived, andstand_in_forshould never pick a candidate that fails that check (or that fails aget_frame_parameters/ first-block decode). TheHillWall→Ice_LakeHrlcopy above is a real instance..nupholds base + update (25.6 GB here) and still has 5.5 GB of zeros.A synthetic reproduction without any game data should be possible: take a verified
.nup, zero a stretch that starts a few KB inside oneTex/*.zsmember and runs through several thousand members;--verifylists them,make_game.pybuilds with stand-ins, the game crashes before the first frame.Where in the game
Boot, before the first frame (black window). Never reaches the title screen.
How often
Every time
Graphics card and driver version
NVIDIA GeForce RTX 5090, NVIDIA 621.14 (driver 0x9b438000, Vulkan 1.4; mesh shaders yes)
CPU, RAM and operating system
AMD Ryzen 7 7800X3D, 32 GB, Windows 11 Pro 25H2 (build 26200)
Changes from the defaults
No in-game options changed (the game never gets that far). No
hookshot_env.txtnow;RX_VK_NO_MESH=1was tried in it for one run, changed nothing, and was removed. DLSS was selected in the Builder.Vulkan implicit layers registered on this PC, not disabled for these runs: Steam overlay and Fossilize, Epic Online Services overlay, OBS, Overwolf, RivaTuner Statistics Server, SCSKiller.
The crash is in the game's resource loader on a non-render thread before the first frame, reproduces identically across runs, and changes when the romfs changes, so I don't think the layers are involved, but I can test with them disabled if you want.
Other software hooked into the game
Yes (named under "Changes from the defaults")
hookshot_log.txt
Pasted inline (collapsed) because I'm filing from a browser that cannot upload files; I can attach the file in a comment if you prefer. This is the latest run; the four rotated logs before it end in the same crash. The user folder in paths is redacted to
<user>.hookshot_log.txt
Screenshots or video
No response
Before you send it
I reproduced the damaged stand-in selection on current main with a small authored NUP, without using the reported dump. The verifier caught both bad members, but fresh and resumed extraction only marked the one with the invalid prefix. The other bad member was then selected as the closest stand-in.
I'll take the stand-in integrity part of this report. S1 because the resulting build can remain unable to boot, affected share unknown, confidence 1.0 for the synthetic donor-selection reproduction on Windows. The cutoff for severely damaged dumps can be discussed separately. Claim in #dev-work.
I am also taking the unresolved-resource build gate. A small authored fixture on main returns normally with a damaged file that has no replacement, writes the successful-check marker, and silently skips the same file on retry. The proposed change stops before lift when a resource is still unrepaired, preserves retry evidence and rechecks legacy markers. Fully repairable extractions keep their existing path.
S1, confidence 1.0 for the game-free reproduction. Reach is unknown within damaged dumps, with all Builder platforms as the upper bound. This is separate from the donor-integrity change in #2019. Claim in dev-work.
Real-world data point for the donor-integrity work: two separate downloads of the same
.nuptorrent produced byte-identical damage in the same 3 texture files, so this was a bad source, not transfer noise. The builder-selected stand-ins were: FairyFountain floor normal → sand variant; Ganon-stage bake..._d0_t0→..._d0_t2variant; WaterTemple gate rockM_01→P_01variant. Full details in #2237. (No game data involved — file names and builder output only.)Thanks for the report. Reports of the same problem are now collected in #2505, which lists this one with your details and links back here, so one fix closes them together and the open list stays readable. Follow #2505 for the fix, and add new details there (or here). If this turns out to be a separate problem it will be reopened.
Thank you, keep up the great work.