Summary
A jointed multi-part sub-level assembly on our server became permanently unloadable: its block data is intact in storage, /sable storage find_all_sub_levels lists it, but it never instantiates in the world and cannot be targeted by any command. The server logs Sub-level dependency does not exist in chunk. Something has gone terribly wrong.
The cause appears to be that mutually-dependent sub-levels cannot bootstrap: each part lists the others in loading_dependencies, dependency resolution only looks at sub-levels already present in loaded chunks, so if the whole group is unloaded at once, none of them can ever load again.
Environment
- Sable 2.0.3 (
sable-neoforge-1.21.1-2.0.3.jar), Sable Companion
- Create 6.0.10, Create: Aeronautics 1.3.0 (bundled)
- Minecraft 1.21.1, NeoForge 21.1.233, dedicated server, Java 21
Symptom
A named airship (Hellicarrier, ~3200 blocks, 68 blocks across, 32 chunk sections) is invisible in the world. Flying a player to its stored coordinates shows empty air. Neighbouring sub-levels in the same region load normally at the same moment, so it is not a chunk-loading problem.
[Server thread/ERROR] [dev.ryanhcode.sable.Sable/]: Sub-level dependency does not exist in chunk. Something has gone terribly wrong.
(logged once per part of the assembly)
What the data shows
The assembly is 4 sub-levels stored in r.-1.27.0.slvls, slots 2/3/4/5. Each one lists the other three in loading_dependencies:
| slot |
uuid |
depends on |
| 2 |
9aa0dd6c |
4c59497b, dba13ad9, 46b9180a |
3 (Hellicarrier) |
46b9180a |
4c59497b, dba13ad9, 9aa0dd6c |
| 4 |
dba13ad9 |
4c59497b, 46b9180a, 9aa0dd6c |
| 5 |
4c59497b |
dba13ad9, 46b9180a, 9aa0dd6c |
All four dependency targets exist in storage — verified by decoding every sub-level UUID on the server (248 of them). Nothing is missing; the block data of all four parts is intact and parses cleanly.
Additionally, none of the four had a record in the chunk map (.slvlr) pointing at their storage slot, while healthy sub-levels in the same region did. The four parts sit in four different chunks ([-20,888], [-21,889] ×2, [-21,887]).
What we tried
- Rebuilt the chunk-map records — wrote
pointers entries in .slvlr for the chunk containing each part's world position (matching the convention used by working sub-levels: chunk = floor(pos/16), table slot = (cx & 31) + (cz & 31) * 32). Verified the records survived a restart and that zero sub-levels were left unreferenced. The assembly still did not load.
- Player presence at the coordinates — other sub-levels ~70 blocks away loaded fine in the same tick; these four did not.
/sable teleport, /sable info with @e[distance=…], @n — all return No sub-levels found, since the selector only sees instantiated sub-levels.
Likely cause
Dependency resolution looks for the dependencies among sub-levels already loaded in chunks, rather than resolving them from storage. For a group whose members only depend on each other, there is no entry point: loading part A requires B, C, D to already be present, and vice-versa. As long as the whole group is unloaded simultaneously, it can never come back.
Possible contributing factor: runaway velocities
While investigating, we found sub-levels persisted with extreme velocities in their NBT (linear_velocity), the worst at ~46 000 blocks/s, several in the 1 000–9 000 range, and one with angular_velocity ≈ 2 085 rad/s. These travel kilometres between autosaves, crossing region files as they go (we watched one migrate r.8.29 → r.10.27 within minutes). That churn seems a plausible way for a group's chunk-map registration to end up lost or desynchronised — which is exactly the state we found this assembly in.
Zeroing those velocity fields offline stopped all of them dead (verified: zero movement across repeated samples), with no other side effects.
Impact
A player's largest build is intact on disk but permanently unreachable, with no in-game way to recover it — remove, teleport and info all require the sub-level to be loaded first.
Suggested fixes
- Resolve
loading_dependencies from storage rather than only from loaded chunks, or load a dependency group atomically.
- Clamp or sanity-check persisted velocities on save/load — a 46 000 blocks/s sub-level is never legitimate and causes the region churn above.
- A recovery path for orphaned sub-levels (e.g.
/sable storage repair, or letting teleport/remove target entries by UUID from storage, since find_all_sub_levels can already list them).
Notes
Happy to supply the region files, the full dependency dump, or test a patch — this reproduces reliably here.
Related: #1386 (empty chunk-map records never pruned), found on the same server while debugging autosave stalls.
Summary
A jointed multi-part sub-level assembly on our server became permanently unloadable: its block data is intact in storage,
/sable storage find_all_sub_levelslists it, but it never instantiates in the world and cannot be targeted by any command. The server logsSub-level dependency does not exist in chunk. Something has gone terribly wrong.The cause appears to be that mutually-dependent sub-levels cannot bootstrap: each part lists the others in
loading_dependencies, dependency resolution only looks at sub-levels already present in loaded chunks, so if the whole group is unloaded at once, none of them can ever load again.Environment
sable-neoforge-1.21.1-2.0.3.jar), Sable CompanionSymptom
A named airship (
Hellicarrier, ~3200 blocks, 68 blocks across, 32 chunk sections) is invisible in the world. Flying a player to its stored coordinates shows empty air. Neighbouring sub-levels in the same region load normally at the same moment, so it is not a chunk-loading problem.(logged once per part of the assembly)
What the data shows
The assembly is 4 sub-levels stored in
r.-1.27.0.slvls, slots 2/3/4/5. Each one lists the other three inloading_dependencies:9aa0dd6c4c59497b,dba13ad9,46b9180aHellicarrier)46b9180a4c59497b,dba13ad9,9aa0dd6cdba13ad94c59497b,46b9180a,9aa0dd6c4c59497bdba13ad9,46b9180a,9aa0dd6cAll four dependency targets exist in storage — verified by decoding every sub-level UUID on the server (248 of them). Nothing is missing; the block data of all four parts is intact and parses cleanly.
Additionally, none of the four had a record in the chunk map (
.slvlr) pointing at their storage slot, while healthy sub-levels in the same region did. The four parts sit in four different chunks ([-20,888],[-21,889]×2,[-21,887]).What we tried
pointersentries in.slvlrfor the chunk containing each part's world position (matching the convention used by working sub-levels: chunk =floor(pos/16), table slot =(cx & 31) + (cz & 31) * 32). Verified the records survived a restart and that zero sub-levels were left unreferenced. The assembly still did not load./sable teleport,/sable infowith@e[distance=…],@n— all returnNo sub-levels found, since the selector only sees instantiated sub-levels.Likely cause
Dependency resolution looks for the dependencies among sub-levels already loaded in chunks, rather than resolving them from storage. For a group whose members only depend on each other, there is no entry point: loading part A requires B, C, D to already be present, and vice-versa. As long as the whole group is unloaded simultaneously, it can never come back.
Possible contributing factor: runaway velocities
While investigating, we found sub-levels persisted with extreme velocities in their NBT (
linear_velocity), the worst at ~46 000 blocks/s, several in the 1 000–9 000 range, and one withangular_velocity≈ 2 085 rad/s. These travel kilometres between autosaves, crossing region files as they go (we watched one migrater.8.29→r.10.27within minutes). That churn seems a plausible way for a group's chunk-map registration to end up lost or desynchronised — which is exactly the state we found this assembly in.Zeroing those velocity fields offline stopped all of them dead (verified: zero movement across repeated samples), with no other side effects.
Impact
A player's largest build is intact on disk but permanently unreachable, with no in-game way to recover it —
remove,teleportandinfoall require the sub-level to be loaded first.Suggested fixes
loading_dependenciesfrom storage rather than only from loaded chunks, or load a dependency group atomically./sable storage repair, or lettingteleport/removetarget entries by UUID from storage, sincefind_all_sub_levelscan already list them).Notes
Happy to supply the region files, the full dependency dump, or test a patch — this reproduces reliably here.
Related: #1386 (empty chunk-map records never pruned), found on the same server while debugging autosave stalls.