Skip to content

Fix Fabric dedicated server client class linkage - #745

Merged
st0x0ef merged 2 commits into
architectury:26.2from
awkwardusername:26.2
Sep 10, 2026
Merged

st0x0ef merged 2 commits into
architectury:26.2from
awkwardusername:26.2

Conversation

@awkwardusername

@awkwardusername awkwardusername commented Sep 10, 2026 •

Copy link
Copy Markdown

Fixes #744.

Fabric dedicated servers can fail during Architectury common initialization because client callback lambdas on the shared event implementation reference client-only classes. Move those registrations into a client-only implementation, dispatched through a common ClientEventHandler platform declaration under the existing client environment guard. Shared EventHandlerImpl no longer contains a client registration method. NeoForge retains its existing automatic client event subscribers and empty platform registration behavior.

Verification

Results below apply to revision ce6de36a8f9daf78c696c9e28b7aea4f71ede706 unless noted otherwise.

Environment Result
Fabric and NeoForge builds Both pass. Packaged bytecode dispatches the new common declaration to the corresponding public platform implementation. Test tasks contain no automated tests (NO-SOURCE).
Fabric production dedicated server, Windows Minimal environment reaches Done and shuts down cleanly: Minecraft 26.2, Loader 0.19.5, Fabric API 0.160.0+26.2, Java 25.
Fabric production dedicated server, Ubuntu under WSL2 Same minimal mod set, Temurin 25.0.4.1+1: reaches Done (4.677s), accepts stop, saves, and exits 0.
Fabric production client, Windows / full pack Startup, resource loading, and multiplayer world join pass, with no entrypoint, class-linkage, or access errors.
NeoForge production dedicated server, Ubuntu under WSL2 Minecraft 26.2, NeoForge 26.2.0.82, Temurin 25.0.4.1+1, Architectury as the only user mod: reaches Done (4.574s), accepts stop, saves all dimensions, and exits 0 with no Java process remaining.
NeoForge development client, Windows :testmod-neoforge:runClient, NeoForge 26.2.0.82, Zulu 25.0.4: startup, resource loading, singleplayer world join, and client/server join callbacks pass. See shutdown limitation below. This was a development run, not an installed production-client test.

The previous revision also passed full-pack Fabric dedicated-server startup; the revised dedicated-server tests above use isolated minimal environments.

Runtime caveats

  • The NeoForge development client emitted client-stopping and server-stopped callbacks and saved its integrated-server world, but its JVM remained alive with non-daemon executor threads. A later shutdown-watchdog exception reported ServerWatchdog unavailable after Module minecraft has been closed. Logs and a thread dump were preserved, then the leftover process was terminated, making the Gradle run exit nonzero. This is not a clean process-exit pass. No baseline comparison has established whether this behavior is related to this PR.
  • The NeoForge production server logged a nonfatal Log4j/Netty kqueue.Native initialization exception (Only supported on OSX/BSD) before continuing to Done and clean shutdown. The stack had no Architectury frames; ownership has not been established.
  • Individual callback cancellation paths have not been instrumented.

Source and platform checks

An independent Astra High code review found no actionable regression. The extracted Fabric registration body is unchanged apart from whitespace, initialization ordering and the existing guard are preserved, and NeoForge automatic subscribers are unchanged. This is AI-assisted source/bytecode review, not maintainer approval or additional runtime coverage.

The revised bridge follows Architectury Plugin's existing @ExpectPlatform convention; no plugin change is required by this fix. Both packaged platform targets were checked. Separate documentation clarifications are staged in the docs fork; no docs PR has been opened, and those changes are not a dependency of this PR.

Released 21.1.8 reproduction

A fresh download from https://modrinth.com/mod/architectury-api/version/21.1.8+fabric reproduces the failure on a production dedicated server before any client connects.

  • Windows, Zulu OpenJDK 25.0.4; Minecraft 26.2; Fabric Loader 0.19.5.
  • Only two files in mods: architectury-fabric-21.1.8.jar and fabric-api-0.160.0+26.2.jar.
  • Launch with java -Xms512M -Xmx1G -jar server.jar nogui using the Fabric production server launcher (installer 1.1.2), with the EULA accepted.
  • Architectury SHA-256: a266a90b68e9a051c4c83f40568a875944350b2a026ead87a2b056b067465156 (identical to the originally tested artifact).
Could not execute entrypoint stage 'main' ... provided by 'architectury'
Caused by: java.lang.NoClassDefFoundError: net/minecraft/client/multiplayer/ClientLevel
    at knot//dev.architectury.event.EventHandler.registerCommon(EventHandler.java)
    at knot//dev.architectury.event.EventHandler.init(EventHandler.java:37)

The same released JAR also fails common initialization in an isolated Ubuntu 24.04.5 / WSL2 production server with Temurin 25.0.4.1+1 and the same two-mod set:

Caused by: java.lang.NoClassDefFoundError: net/fabricmc/fabric/api/client/rendering/v1/level/AbstractLevelRenderContext

Neither released-JAR server reaches Done. The minimal Windows server reports ClientLevel; the WSL server reports AbstractLevelRenderContext; the original full-pack failure reported LocalPlayer. The WSL comparison also changes JVM vendor/version, so it does not isolate the operating system as the only variable. No minimal client/server pair with released 21.1.8 was tested; the failure occurs during server startup independently of a client.

@CLAassistant

CLAassistant commented Sep 10, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

ClientLevelRenderEvent.AFTER_TRANSLUCENT_BLOCKS.invoker().render(new LevelSubmitContextImpl(context)));
LevelRenderEvents.END_MAIN.register(context ->
ClientLevelRenderEvent.AFTER_TRANSLUCENT_PARTICLES.invoker().render(new LevelSubmitContextImpl(context)));
ClientEventHandlerImpl.registerClient();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably remove this completely and move the call to a new ClientEventHandler.

import net.minecraft.resources.Identifier;

@Environment(EnvType.CLIENT)
final class ClientEventHandlerImpl {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't use Impl if you don't have a base class. In this case it could be good to create one.

@st0x0ef st0x0ef left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks for your contribution

st0x0ef added a commit that referenced this pull request Sep 10, 2026
@st0x0ef
st0x0ef merged commit d2875d4 into architectury:26.2 Sep 10, 2026
2 checks passed
@awkwardusername
awkwardusername deleted the 26.2 branch September 10, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants