You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When it happened, I was trying to use Create: Aeronautics to turn the ship my friend and I built into a sub-level. The conversion process went pretty smoothly, but since the ship was originally built on the water and partly underwater, the underwater blocks got pulled into the sub-level too. Sponges can absorb these water blocks, which I actually did… then I saw the client reported the connection was terminated, and the server output a crash message...
From my experience, I think it's because:
Sable will try to remove any sub-level that only contains fluids (I'll call this α below)
It will split a sub-level that has no connecting blocks in the middle into two sub-levels (call this β below)
The sub-level’s physics simulation (call this γ below)
conflicted with each other.
When I tried to drain our ship, the sub-level looked roughly like this:
boat
waterA <-HERE
waterB
I placed a sponge at '<-HERE>', absorbing waterA, so there were no connecting blocks between waterB and boat. β split waterB and the boat into two sub-levels (let’s call the separated waterB 'waterC', and the separated boat 'boat1'), and γ tried to simulate the physical state of waterC, but it had already been removed by α!
This text comes from Bing Translate. If you can't understand it, you can copy the untranslated original text to AI.
Similarly, when a player shoots a flame arrow at a sub-level that only has one TNT block, the game will also crash, because Sable tries to track a TNT sub-level that has already exploded.
All of this is because the damn physics simulation didn't check if the sub-level still exists in the world!
同样,当玩家用火焰箭射击一个只有一个TNT方块的物理结构时,游戏也会崩溃,因为Sable会尝试追踪一个已经爆炸的TNT物理结构。
这一切都是该死的物理模拟没有效验物理结构是否依然存在于世界中
Additional Sable 2.0.5 case: split/removed-plot crash with a surviving airship later stranded in storage
I have a real-world case with the exact exception in this issue, plus enough retained storage/log data to show what happened to the surviving airship afterward.
Environment
Minecraft 1.21.1
NeoForge 21.1.249
Sable 2.0.5
Sable Companion 1.6.0
Create 6.0.10
Create Aeronautics 1.3.1
Create Gadgets & Gizmos 1.1.3
Create Propulsion: Simulated 1.1.5
Waystones 21.1.41
WaystonesSable 1.0.7
Single-player integrated server
Structure setup
The main structure was a large flying castle, eventually named castle.
Separately, my kid found a random vanilla village hut, assembled the hut into its own Sable sublevel at the village, and later moved/placed that already-assembled hut sublevel inside the castle.
The hut was not assembled from blocks while inside the castle.
User-visible action around the later failure
We remember breaking/deleting a Waystone immediately before one of the visible failures (the game crashed).
I do not want to over-attribute that to Waystones. Minecraft does not log an ordinary block break, and the retained crash stack contains no Waystones frame. Breaking the Waystone may simply have changed block connectivity and caused Sable's heat-map/splitting logic to run against state that was already inconsistent.
Important pre-existing-state caveat
The world appears to have already had Sable trouble before the later hut/Waystone incident.
In the earliest retained Aug 30 session, Sable logs:
[02:49:56.464] [Render thread/ERROR] [dev.ryanhcode.sable.Sable/]:
Received a sub-level movement packet for a non-existent sub-level
Later in that same session, Sable repeatedly fails to restore the eventual castle UUID:
[03:16:12.713] [Server thread/ERROR] [dev.ryanhcode.sable.Sable/]:
Attempted to snatch sub-level with ID
global->[chunkPos=[-41, 11], storageIndex=0, subLevelIndex=0]
stored at 845625ba-98c8-461a-93b5-da56312c9109,
but the requested sub-level wasn't present in the holding chunk
WaystonesSable then reports that the same stored sublevel cannot be restored for a Waystone target when we tried teleporting back via a bound scroll.
There was a separate Immersive-Aeronautics/portal experiment the previous night that crashed the world; that mod was removed afterward and is already absent from the retained 02:48+ mod lists. This is a plausible source of earlier bad state, but I do not have an earlier log proving that attribution.
So the strongest claim here is: the world already contained at least one stale/non-live Sable state before the later crash.
Exact Sable crash
On Aug 30 at 09:34:21 the integrated server crashes with the same exception reported here:
java.lang.RuntimeException: Sub-level assembly attempted inside plot of already removed sub-level
at dev.ryanhcode.sable.api.SubLevelAssemblyHelper.assembleBlocks(SubLevelAssemblyHelper.java:85)
at dev.ryanhcode.sable.sublevel.plot.heat.SubLevelHeatMapManager.split(SubLevelHeatMapManager.java:242)
at dev.ryanhcode.sable.sublevel.plot.heat.SubLevelHeatMapManager.step(SubLevelHeatMapManager.java:118)
at dev.ryanhcode.sable.sublevel.plot.heat.SubLevelHeatMapManager.tick(SubLevelHeatMapManager.java:85)
at dev.ryanhcode.sable.sublevel.ServerSubLevel.tick(ServerSubLevel.java:235)
A second crash at 10:03:05 has the same Sable split stack.
Immediately before the 09:34 crash, the live/storage mismatch is already visible:
[09:31:17.168] [Sable/ERROR]:
Attempted to snatch sub-level with ID
global->[chunkPos=[-13, 46], storageIndex=0, subLevelIndex=0]
stored at 845625ba-98c8-461a-93b5-da56312c9109,
but the requested sub-level wasn't present in the holding chunk
[09:31:17.168] [WaystonesSable/WARN]:
Sable did not load SubLevel 845625ba-98c8-461a-93b5-da56312c9109
for target Waystone a41cd7eb-c0f1-49e0-ae1b-945f68376857 ...
[09:33:34.873] [Sable/ERROR]:
Received a sub-level movement packet for a non-existent sub-level
Aftermath: the surviving castle becomes storage-only
After restarting, the castle remained visible to /sable storage find_all_sub_levels, but normal live-sublevel commands/selectors could not target it.
A later restart logs:
[10:04:17.189] [Sable/ERROR]:
Couldn't find sub-level at index 0 in storage file for chunk [9, 65]
[10:04:17.189] [Sable/ERROR]:
Due to a failed storage sub-level data load, we can't add a holding sub-level
for pointer local->[storageIndex=0, subLevelIndex=0].
This will cause issues later down the line.
[10:04:17.191] [Sable/ERROR]:
Sub-level dependency does not exist in chunk. Something has gone terribly wrong.
That appears to connect this runtime split/remove failure directly to the storage/bootstrap failure tracked in #1387.
Offline storage inspection and verified recovery
I investigated the damaged save collaboratively with ChatGPT (GPT-5.6 Sol), which decoded the Sable .slvlr / .slvls storage; I verified the repair by loading the castle successfully in-game.
Castle UUID:
845625ba-98c8-461a-93b5-da56312c9109
In the damaged storage we found:
the castle's actual .slvls block payload was intact and parsed cleanly;
the castle holding-chunk pointer list contained [0, 1];
slot 1 pointed to the intact castle;
slot 0 was empty/dead;
the castle's loading_dependencies referenced UUID 89ff0293-8292-4e32-8b0c-dbcd19584fad;
that UUID's payload still existed in another storage file and decoded as the small village-hut-like sublevel;
the two had mutual loading-dependency state.
A minimal offline repair:
removed the dead holding-chunk pointer,
removed the stale/missing dependency from the castle, and
zeroed the castle's saved velocity.
The castle then instantiated normally, with its block payload intact.
Why this seems useful for this issue
This case suggests the already removed sub-level crash can have a persistent consequence:
a sublevel/plot becomes removed or invalidated;
SubLevelHeatMapManager.split() still attempts to assemble against that removed plot;
the server crashes;
pointer/dependency cleanup is not left in a self-consistent state;
a surviving large sublevel later exists on disk but cannot bootstrap into the live world.
That makes this look related to #1387 rather than only a transient crash.
Evidence
I have attached one ZIP containing:
retained logs 2026-08-30-1.log.gz through 2026-08-30-6.log.gz;
I can also provide the damaged Sable sublevels/ directory and the successfully repaired version if that is useful for a regression fixture.
For a future test, I plan to focus first on Sable alone: trigger connectivity splitting while a related sublevel/plot is removed, assert that the split path never assembles against an already-removed plot, then unload/reload and verify no dead pointer or stale dependency survives.
A deterministic reproduction on Sable 2.0.6 (NeoForge 21.1.248, dedicated server), and the cause.
Cause.SubLevelHeatMapManager.split() assembles the cut-off pieces one after another. Moving a piece's blocks out of the parent is a block change on the parent. If what is left of the parent has no mass (only blocks without a collision shape), SubLevelPhysicsSystem destroys the parent's remaining blocks and marks it removed, inside that loop. The next iteration's assembleBlocks then finds its containing sub-level removed and throws. On our server the shutdown save then failed as well (Body has been removed from SubLevelSerializer.serialize), so the level was not saved and the JVM stayed up without a server thread until the watchdog killed it.
Reproduction (any world, area force-loaded; minecraft:light has no mass but is not air):
setblock 0 150 60 minecraft:light
setblock 1 150 60 minecraft:light
setblock 2 150 60 minecraft:stone
setblock 3 150 60 minecraft:light
setblock 1 150 61 minecraft:stone
setblock 1 150 62 minecraft:stone
sable assemble area 0 150 60 3 150 62
# first sub-level of a fresh world: the anchor (0,150,60) lands on the plot centre block (20481032, 128, 20481032)
fill 20481033 128 20481032 20481034 128 20481033 minecraft:air replace minecraft:stone
The /fill removes both stone connectors in one command, leaving two pieces: a light block and a stone block. In this order the stone piece is assembled first, the parent keeps only light blocks, is removed, and the light piece's assembly crashes (split:242 <- step:187). With the two pieces swapped (the light one assembled first, dropped as zero mass) there is no crash.
Fix we run (as a bytecode patch; the source equivalent):
for (finalList<BlockPos> blocks : newSubLevelBlocks.values()) {
if (this.subLevel.isRemoved()) break;
...
Nothing is lost by stopping: a parent is only marked removed here after its plot's blocks were destroyed. With it, the crash order above ends with one sub-level (the stone piece) at 20 TPS, and a plain three-stone bar cut in the middle still splits into two.
Activity
createmeow commentedon Jul 24, 2026
Similarly, when a player shoots a flame arrow at a sub-level that only has one TNT block, the game will also crash, because Sable tries to track a TNT sub-level that has already exploded.
All of this is because the damn physics simulation didn't check if the sub-level still exists in the world!
同样,当玩家用火焰箭射击一个只有一个TNT方块的物理结构时,游戏也会崩溃,因为Sable会尝试追踪一个已经爆炸的TNT物理结构。
这一切都是该死的物理模拟没有效验物理结构是否依然存在于世界中
JamesXNelson commentedon Aug 30, 2026
Additional Sable 2.0.5 case: split/removed-plot crash with a surviving airship later stranded in storage
I have a real-world case with the exact exception in this issue, plus enough retained storage/log data to show what happened to the surviving airship afterward.
Environment
Structure setup
The main structure was a large flying castle, eventually named
castle.Separately, my kid found a random vanilla village hut, assembled the hut into its own Sable sublevel at the village, and later moved/placed that already-assembled hut sublevel inside the castle.
The hut was not assembled from blocks while inside the castle.
User-visible action around the later failure
We remember breaking/deleting a Waystone immediately before one of the visible failures (the game crashed).
I do not want to over-attribute that to Waystones. Minecraft does not log an ordinary block break, and the retained crash stack contains no Waystones frame. Breaking the Waystone may simply have changed block connectivity and caused Sable's heat-map/splitting logic to run against state that was already inconsistent.
Important pre-existing-state caveat
The world appears to have already had Sable trouble before the later hut/Waystone incident.
In the earliest retained Aug 30 session, Sable logs:
Later in that same session, Sable repeatedly fails to restore the eventual castle UUID:
WaystonesSable then reports that the same stored sublevel cannot be restored for a Waystone target when we tried teleporting back via a bound scroll.
There was a separate Immersive-Aeronautics/portal experiment the previous night that crashed the world; that mod was removed afterward and is already absent from the retained 02:48+ mod lists. This is a plausible source of earlier bad state, but I do not have an earlier log proving that attribution.
So the strongest claim here is: the world already contained at least one stale/non-live Sable state before the later crash.
Exact Sable crash
On Aug 30 at 09:34:21 the integrated server crashes with the same exception reported here:
A second crash at 10:03:05 has the same Sable split stack.
Immediately before the 09:34 crash, the live/storage mismatch is already visible:
Aftermath: the surviving castle becomes storage-only
After restarting, the castle remained visible to
/sable storage find_all_sub_levels, but normal live-sublevel commands/selectors could not target it.A later restart logs:
That appears to connect this runtime split/remove failure directly to the storage/bootstrap failure tracked in #1387.
Offline storage inspection and verified recovery
I investigated the damaged save collaboratively with ChatGPT (GPT-5.6 Sol), which decoded the Sable
.slvlr/.slvlsstorage; I verified the repair by loading the castle successfully in-game.Castle UUID:
845625ba-98c8-461a-93b5-da56312c9109In the damaged storage we found:
.slvlsblock payload was intact and parsed cleanly;[0, 1];1pointed to the intact castle;0was empty/dead;loading_dependenciesreferenced UUID89ff0293-8292-4e32-8b0c-dbcd19584fad;A minimal offline repair:
The castle then instantiated normally, with its block payload intact.
Why this seems useful for this issue
This case suggests the
already removed sub-levelcrash can have a persistent consequence:SubLevelHeatMapManager.split()still attempts to assemble against that removed plot;That makes this look related to #1387 rather than only a transient crash.
Evidence
I have attached one ZIP containing:
2026-08-30-1.log.gzthrough2026-08-30-6.log.gz;sable-issue-evidence-bundle.zip
I can also provide the damaged Sable
sublevels/directory and the successfully repaired version if that is useful for a regression fixture.For a future test, I plan to focus first on Sable alone: trigger connectivity splitting while a related sublevel/plot is removed, assert that the split path never assembles against an already-removed plot, then unload/reload and verify no dead pointer or stale dependency survives.
Petroid2470 commentedon Oct 5, 2026
I think i hit the same crash, happened on dedicated server then i was able to reproduce it in singleplayer
Minecraft 1.21.1
Neoforge 21.1.230
Sable 2.0.5
Crash Report:
https://mclo.gs/zANiDCR
Video of how i caused the crash:
https://youtu.be/IYgkKwOptVg
anenigmabeyondwords commentedon Oct 12, 2026
A deterministic reproduction on Sable 2.0.6 (NeoForge 21.1.248, dedicated server), and the cause.
Cause.
SubLevelHeatMapManager.split()assembles the cut-off pieces one after another. Moving a piece's blocks out of the parent is a block change on the parent. If what is left of the parent has no mass (only blocks without a collision shape),SubLevelPhysicsSystemdestroys the parent's remaining blocks and marks it removed, inside that loop. The next iteration'sassembleBlocksthen finds its containing sub-level removed and throws. On our server the shutdown save then failed as well (Body has been removedfromSubLevelSerializer.serialize), so the level was not saved and the JVM stayed up without a server thread until the watchdog killed it.Reproduction (any world, area force-loaded;
minecraft:lighthas no mass but is not air):The
/fillremoves both stone connectors in one command, leaving two pieces: a light block and a stone block. In this order the stone piece is assembled first, the parent keeps only light blocks, is removed, and the light piece's assembly crashes (split:242 <- step:187). With the two pieces swapped (the light one assembled first, dropped as zero mass) there is no crash.Fix we run (as a bytecode patch; the source equivalent):
Nothing is lost by stopping: a parent is only marked removed here after its plot's blocks were destroyed. With it, the crash order above ends with one sub-level (the stone piece) at 20 TPS, and a plain three-stone bar cut in the middle still splits into two.