Architectury Transformer crashes on NeoForge with StringIndexOutOfBoundsException
Environment
Minecraft Version: 1.21.10
Architectury Loom: 1.11.458
Architectury Plugin: 3.4.162
Architectury Transformer Runtime: 5.2.87
NeoForge: 21.4.31-beta
Gradle: 9.1.0
JDK: 21.0.8
OS: Windows
Description
The Architectury runtime transformer crashes when launching a NeoForge client with StringIndexOutOfBoundsException during the removeDuplicates phase. The Fabric client runs without issues.
Stack Trace
[Architectury Transformer] Architectury Runtime 5.2.87
[Architectury Transformer] Read classpath in 2.345 s
[Architectury Transformer] Listening at C:\Users...\common\build\devlibs\pocket_villagers-1.0.0-1.21.10-dev.jar
java.lang.StringIndexOutOfBoundsException: Range [0, -1) out of bounds for length 70
at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:55)
at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:52)
at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:213)
at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:210)
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:98)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckFromToIndex(Preconditions.java:112)
at java.base/jdk.internal.util.Preconditions.checkFromToIndex(Preconditions.java:349)
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:4865)
at java.base/java.lang.String.substring(String.java:2834)
at dev.architectury.transformer.TransformerRuntime.lambda$null$8(TransformerRuntime.java:250)
at dev.architectury.transformer.input.BaseFileAccess.handle(BaseFileAccess.java:56)
at dev.architectury.transformer.input.ForwardingFileView.handle(ForwardingFileView.java:42)
at dev.architectury.transformer.TransformerRuntime.lambda$removeDuplicates$9(TransformerRuntime.java:246)
at java.base/java.util.ArrayList.removeIf(ArrayList.java:1755)
at java.base/java.util.ArrayList.removeIf(ArrayList.java:1743)
at dev.architectury.transformer.TransformerRuntime.removeDuplicates(TransformerRuntime.java:240)
at dev.architectury.transformer.TransformerRuntime.main(TransformerRuntime.java:214)
Root Cause
The transformer fails when processing NeoForge's neoform dependency, which is a .zip file rather than a .jar:
C:\Users\Raguto.gradle\caches...\net.neoforged\neoform...\neoform-1.21.4-....zip
The code in TransformerRuntime.java:250 calls String.substring() with an index from lastIndexOf(), which returns -1 when the expected separator isn't found. The transformer assumes all classpath entries follow a specific format (presumably .jar files), and crashes when encountering the .zip artifact.
Why Fabric Works
Fabric doesn't include the neoform .zip dependency, so the transformer never encounters the problematic classpath entry. This is NeoForge-specific.
The transformer should either:
Handle .zip files gracefully without crashing
Skip non-.jar classpath entries
Add a defensive check for lastIndexOf() == -1 before calling substring()
Reproduction
Set up a standard Architectury multi-loader project for MC 1.21.10
Add NeoForge dependency: modImplementation "net.neoforged:neoforge:21.4.31-beta"
Run ./gradlew :neoforge:runClient
Observe crash in transformer
Additional Notes
This appears to be specific to MC 1.21.10 with NeoForge 21.4.x
The issue blocks all NeoForge development for Architectury projects on this version
Fabric builds and runs successfully with the same project structure
Architectury Transformer crashes on NeoForge with StringIndexOutOfBoundsException
Environment
Minecraft Version: 1.21.10
Architectury Loom: 1.11.458
Architectury Plugin: 3.4.162
Architectury Transformer Runtime: 5.2.87
NeoForge: 21.4.31-beta
Gradle: 9.1.0
JDK: 21.0.8
OS: Windows
Description
The Architectury runtime transformer crashes when launching a NeoForge client with StringIndexOutOfBoundsException during the removeDuplicates phase. The Fabric client runs without issues.
Stack Trace
[Architectury Transformer] Architectury Runtime 5.2.87
[Architectury Transformer] Read classpath in 2.345 s
[Architectury Transformer] Listening at C:\Users...\common\build\devlibs\pocket_villagers-1.0.0-1.21.10-dev.jar
java.lang.StringIndexOutOfBoundsException: Range [0, -1) out of bounds for length 70
at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:55)
at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:52)
at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:213)
at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:210)
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:98)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckFromToIndex(Preconditions.java:112)
at java.base/jdk.internal.util.Preconditions.checkFromToIndex(Preconditions.java:349)
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:4865)
at java.base/java.lang.String.substring(String.java:2834)
at dev.architectury.transformer.TransformerRuntime.lambda$null$8(TransformerRuntime.java:250)
at dev.architectury.transformer.input.BaseFileAccess.handle(BaseFileAccess.java:56)
at dev.architectury.transformer.input.ForwardingFileView.handle(ForwardingFileView.java:42)
at dev.architectury.transformer.TransformerRuntime.lambda$removeDuplicates$9(TransformerRuntime.java:246)
at java.base/java.util.ArrayList.removeIf(ArrayList.java:1755)
at java.base/java.util.ArrayList.removeIf(ArrayList.java:1743)
at dev.architectury.transformer.TransformerRuntime.removeDuplicates(TransformerRuntime.java:240)
at dev.architectury.transformer.TransformerRuntime.main(TransformerRuntime.java:214)
Root Cause
The transformer fails when processing NeoForge's neoform dependency, which is a .zip file rather than a .jar:
C:\Users\Raguto.gradle\caches...\net.neoforged\neoform...\neoform-1.21.4-....zip
The code in TransformerRuntime.java:250 calls String.substring() with an index from lastIndexOf(), which returns -1 when the expected separator isn't found. The transformer assumes all classpath entries follow a specific format (presumably .jar files), and crashes when encountering the .zip artifact.
Why Fabric Works
Fabric doesn't include the neoform .zip dependency, so the transformer never encounters the problematic classpath entry. This is NeoForge-specific.
The transformer should either:
Handle .zip files gracefully without crashing
Skip non-.jar classpath entries
Add a defensive check for lastIndexOf() == -1 before calling substring()
Reproduction
Set up a standard Architectury multi-loader project for MC 1.21.10
Add NeoForge dependency: modImplementation "net.neoforged:neoforge:21.4.31-beta"
Run ./gradlew :neoforge:runClient
Observe crash in transformer
Additional Notes
This appears to be specific to MC 1.21.10 with NeoForge 21.4.x
The issue blocks all NeoForge development for Architectury projects on this version
Fabric builds and runs successfully with the same project structure