Skip to content

Crash on LexForge 48.0.32-48.1.0(?) when using java agent that loads URL class early #12

Open

Description

@catfromplan9

Operating System

Windows

Version of Prism Launcher

Prism Launcher 9.4

Version of Qt

Qt 6.8.1

Description of bug

I'm using a java agent, and when I in the premain call code which loads java.net.URL before LexForge initializes, I get the following error when my premain invokes code that initializes java.net.URL:

java.lang.IllegalStateException: Package cpw/mods/niofs/union for module cpw.mods.securejarhandler is already in the unnamed module defined to the class loader
	at java.base/java.lang.Module.defineModule0(Native Method)
	at java.base/java.lang.Module.<init>(Module.java:137)
	at java.base/java.lang.Module.defineModules(Module.java:1183)
	at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
	at io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil.addModules(ModuleUtil.java:92)
	at io.github.zekerzhayard.forgewrapper.installer.Bootstrap.bootstrap(Bootstrap.java:66)
	at io.github.zekerzhayard.forgewrapper.installer.Main.main(Main.java:55)
	at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:105)
	at org.prismlauncher.EntryPoint.listen(EntryPoint.java:129)
	at org.prismlauncher.EntryPoint.main(EntryPoint.java:70)

Followed by this crash not long after:

Exception caught from launcher
java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at io.github.zekerzhayard.forgewrapper.installer.Main.main(Main.java:67)
	at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:105)
	at org.prismlauncher.EntryPoint.listen(EntryPoint.java:129)
	at org.prismlauncher.EntryPoint.main(EntryPoint.java:70)
Caused by: java.lang.Error: factory already defined
	at java.base/java.net.URL.setURLStreamHandlerFactory(URL.java:1228)
	at net.minecraftforge.securemodules.SecureModuleClassLoader.setupModularURLHandler(SecureModuleClassLoader.java:50)
	at net.minecraftforge.securemodules.SecureModuleClassLoader.<clinit>(SecureModuleClassLoader.java:44)
	at net.minecraftforge.bootstrap.BootstrapLauncher.main(BootstrapLauncher.java:117)
	... 8 more
Exiting with ERROR

This problem does not occur on LexForge 48.0.31 or prior, but more importantly, this issue does not occur while using the vanilla launcher. I have been unable to test 1.20.3 on Prism (see #11 for that), but on 1.20.4 running the lowest possible version of LexForge not affected by #11, 49.0.4, this issue does not occur. I assume that this therefore affects 48.0.32 up to 48.1.0 (the last 48.x release), and that it stops triggering under LexForge 49, though only up to 48.1.0 is available for 1.20.2.

Steps to reproduce

  • Create a 1.20.2 instance
  • Install any version of LexForge above 48.0.31
  • Add a java agent that loads java.net.URL in premain to the instance (maybe a dummy new URL())
  • Launch the game

Suspected cause

I assume that the cause is a combination of changes made in LexForge 48.0.32 to the securejarhandler, and more relevantly to Prism Launcher, some sort of flaw with Prism's launch wrapper. That is why this issue should be fixed within Prism, because Prism's launch wrapper is the primary cause for the breakage and the issue does not manifest when using the vanilla launcher.

I asked Lex about this and he speculated the following:

Yup thats Prism not implementing the module system correctly
You'd have to ask them
NIO FileSystems CANT go into a module layer they HAVE to be on the boot class/module path.
The wrapper adding them to a new module is wrong.

This issue is unique

  • I have searched the issue tracker and did not find an issue describing my bug.

Activity

  1. Trial97 commented on Dec 7, 2025

    @Trial97
    Member

    Can you specify which Java agent you are using?
    As from my testing, the only way to achieve this is if the jar agent does something like Class<?> clazz = Class.forName(className); and loads the class with one method, then the ForgeWrapper/Forge Installer loads the same class via import.

  2. TheKodeToad commented on Dec 7, 2025

    @TheKodeToad
    Member

    Instead of whatever we've got going on here https://github.com/PrismLauncher/ForgeWrapper/blob/master/jigsaw/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java maybe we should just pass the arguments directly to java (this wasn't possible in multimc which upstream forgewrapper was made for)

    I don't really understand Java modules but I imagine what we're doing which involves sun.misc.Unsafe and other internals is a pretty bad idea

    This does seem like an edge case so it might take a while to be fixed... (though I have hoped we can remove the jigsaw hacks for a while)

  3. catfromplan9 commented on Dec 8, 2025

    @catfromplan9
    Author

    Can you specify which Java agent you are using? As from my testing, the only way to achieve this is if the jar agent does something like Class<?> clazz = Class.forName(className); and loads the class with one method, then the ForgeWrapper/Forge Installer loads the same class via import.

        private static URLStreamHandler getSystemURLHandler(String protocol) throws Exception {
            URL url = new URL(protocol + ":"); // create a temporary URL
            Field handlerField = URL.class.getDeclaredField("handler");
            long offset = unsafe.objectFieldOffset(handlerField);
            return (URLStreamHandler) unsafe.getObject(url, offset);
        }
    

    I believe it is due to this?

  4. catfromplan9 commented on Dec 8, 2025

    @catfromplan9
    Author

    Instead of whatever we've got going on here https://github.com/PrismLauncher/ForgeWrapper/blob/master/jigsaw/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java maybe we should just pass the arguments directly to java (this wasn't possible in multimc which upstream forgewrapper was made for)

    I don't really understand Java modules but I imagine what we're doing which involves sun.misc.Unsafe and other internals is a pretty bad idea

    This does seem like an edge case so it might take a while to be fixed... (though I have hoped we can remove the jigsaw hacks for a while)

    I appreciate that you're taking the time to think of solutions for this issue, and I understand why this is low priority. Yeah, Lex seems to agree that what you are doing is a bad idea. I am very novice when it comes to java, so I am curious why is it necessary for Prism Launcher to always use a launch wrapper. Do you mind explaining?

  5. Trial97 commented on Dec 8, 2025

    @Trial97
    Member

    Well, Prism uses the wrapper as we need to somehow extract the libraries into a different folder.
    With Vanilla Minecraft launcher, when Forge installs itself, it does so in .minecraft folder, but because Prism needs to support multiple instances, this installation needs to happen in libraries, which is outside the instance root folder.
    Forge installer doesn't support that by default, so we need the wrapper to point the install to there.

  6. Trial97 commented on Dec 8, 2025

    @Trial97
    Member

    Can you see if you can reproduce it with: https://github.com/PrismLauncher/files/blob/master/maven/io/github/zekerzhayard/ForgeWrapper/prism-2025-07-01/ForgeWrapper-prism-2025-07-01.jar

    To test this:

    • copy the mentioned file in the libraries folder from your instance (you can access that folder from instance version settings on the left side there is one libraries)
    • now back to prism in the versions tab select the modloader then hit Customize then Edit
    • this should open <instance root>/patches/net.forge.json (the name may differ so I will update it later)
    • identify the object that contains ForgeWrapper and replace it with:
    {
          "MMC-hint": "local",
          "name": "io.github.zekerzhayard:ForgeWrapper:prism-2025-07-01"
        },
    
    • hit Launch in PrismLauncher

    If this works, then it's a regression on our side because we needed to add the URL in #10 . If this fails may not be fixable

  7. catfromplan9 commented on Dec 8, 2025

    @catfromplan9
    Author

    {
    "MMC-hint": "local",
    "name": "io.github.zekerzhayard:ForgeWrapper:prism-2025-07-01"
    },

    nope, same crash:

    java.lang.IllegalStateException: Package cpw/mods/niofs/union for module cpw.mods.securejarhandler is already in the unnamed module defined to the class loader
    	at java.base/java.lang.Module.defineModule0(Native Method)
    	at java.base/java.lang.Module.<init>(Module.java:137)
    	at java.base/java.lang.Module.defineModules(Module.java:1183)
    	at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
    	at io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil.addModules(ModuleUtil.java:92)
    	at io.github.zekerzhayard.forgewrapper.installer.Bootstrap.bootstrap(Bootstrap.java:66)
    	at io.github.zekerzhayard.forgewrapper.installer.Main.main(Main.java:57)
    	at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:105)
    	at org.prismlauncher.EntryPoint.listen(EntryPoint.java:129)
    	at org.prismlauncher.EntryPoint.main(EntryPoint.java:70)
    

    when I try to access URL early, then a moment later

    Exception caught from launcher
    java.lang.reflect.InvocationTargetException
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
    	at io.github.zekerzhayard.forgewrapper.installer.Main.main(Main.java:69)
    	at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:105)
    	at org.prismlauncher.EntryPoint.listen(EntryPoint.java:129)
    	at org.prismlauncher.EntryPoint.main(EntryPoint.java:70)
    Caused by: java.lang.IllegalArgumentException: Module org.objectweb.asm.commons not known to this layer
    	at java.base/java.lang.ModuleLayer.findLoader(ModuleLayer.java:890)
    	at net.minecraftforge.securemodules.SecureModuleClassLoader.<init>(SecureModuleClassLoader.java:140)
    	at cpw.mods.cl.ModuleClassLoader.<init>(ModuleClassLoader.java:29)
    	at net.minecraftforge.bootstrap.BootstrapLauncher.main(BootstrapLauncher.java:117)
    	... 8 more
    Exiting with ERROR
    

    however on the most up-to-date ForgeWrapper the secondary error is different, please ignore the secondary error I initially attached this issue, it was a mistake on my end with my java agent, this is what I actually get when just accessing URL:

    Exception caught from launcher
    java.lang.reflect.InvocationTargetException
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
    	at io.github.zekerzhayard.forgewrapper.installer.Main.main(Main.java:67)
    	at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:105)
    	at org.prismlauncher.EntryPoint.listen(EntryPoint.java:129)
    	at org.prismlauncher.EntryPoint.main(EntryPoint.java:70)
    Caused by: java.lang.IllegalArgumentException: Module com.google.common not known to this layer
    	at java.base/java.lang.ModuleLayer.findLoader(ModuleLayer.java:890)
    	at net.minecraftforge.securemodules.SecureModuleClassLoader.<init>(SecureModuleClassLoader.java:140)
    	at cpw.mods.cl.ModuleClassLoader.<init>(ModuleClassLoader.java:29)
    	at net.minecraftforge.bootstrap.BootstrapLauncher.main(BootstrapLauncher.java:117)
    	... 8 more
    Exiting with ERROR
    
  8. catfromplan9 commented on Dec 8, 2025

    @catfromplan9
    Author

    actually the secondary error seems to vary each time, so nvm about it being different between ForgeWrappers, but it is always some sort of x not known to this layer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions