Skip to content

Velocity: session proposals rejected with IllegalStateException ("server channel initializer is unavailable") against a SNAPSHOT Velocity build #144

Description

@louij2

Bug description

Real player sessions proposed by the WatchService are consistently rejected
by the Velocity connector with IllegalStateException. The client sees this
as a hang/timeout, not a clean disconnect -- neither a real Java client nor a
synthetic status-ping/login probe ever receives a response once a session is
proposed.

Environment

  • connect-velocity.jar v0.15.5 (latest as of filing)
  • Velocity 4.1.0-SNAPSHOT (git-00759e52-b16) -- a pinned development
    build, not a standard/stable Velocity release
  • Endpoint claimed via the dashboard, token configured in token.json,
    software type set to Velocity
  • Plugins alongside Connect: LuckPerms, Geyser-Velocity + Floodgate,
    a small custom hub-command plugin

Observed behavior

Console log, repeated 3 times over a ~7 hour window whenever a real session
was proposed:

Rejected one Connect session proposal (category=IllegalStateException); keeping WatchService active

The WatchService itself stays healthy (Started watching for new player sessions after each), so this is not a connectivity problem -- proposals
are reaching the connector and being actively rejected.

Root cause (found by reading the source, not guessed)

velocity/src/main/java/com/minekube/connect/inject/velocity/VelocityInjector.java,
CurrentVelocityChannelInitializer.initChannel:

ChannelInitializer<Channel> initializer = currentInitializer.get();
if (initializer == null) {
    throw new IllegalStateException("Velocity server channel initializer is unavailable");
}

currentInitializer re-reads Velocity's internal cm.serverChannelInitializer
holder via reflection on every tunneled connection (by design, per the
comment above it, so plugins that wrap the holder after Connect starts are
still picked up). For us, that reflective .get() call returns null for
every real session.

Suspected cause

This network is pinned to a Velocity SNAPSHOT build
(4.1.0-SNAPSHOT git-00759e52-b16), not a standard release. Connect's
Velocity integration works entirely through reflection into
ConnectionManager's private fields (cm, serverChannelInitializer,
workerGroup, SERVER_WRITE_MARK) -- there is no supported API for this.
It's plausible this particular build's internal structure/timing around
serverChannelInitializer differs enough from what the reflection code
expects to produce a null read at connection time, even though the same
reflection succeeds once at inject() time (no error is logged there, and
the "channel initializer has been replaced" log line confirms the initial
swap succeeds).

Not confirmed against Velocity's source for this exact SNAPSHOT commit --
flagging the correlation since it's the one thing about our setup that
isn't a standard release build.

Isolation work done before filing

Ruled out before concluding this is a Velocity-build issue rather than a
config mistake on our end:

  • Not a Geyser/Floodgate conflict: removed both entirely, restarted with
    a bare Velocity + LuckPerms + Connect stack, retested against the same
    endpoint -- identical failure.
  • Not an unclaimed-endpoint limitation: endpoint was claimed via the
    dashboard (app.minekube.com), software type set to Velocity, token
    reset and deployed to token.json -- identical failure, endpoint still
    shows "Inactive" in the dashboard.
  • Not a network/firewall problem: outbound HTTPS to
    watch-connect.minekube.net returns a real response (not a timeout); DNS
    for the assigned *.play.minekube.net resolves to a real anycast IP; raw
    TCP connects immediately.
  • Not a wrong-plugin-binary issue: the jar downloaded fresh from the
    dashboard's Velocity-specific download link is byte-identical (SHA256) to
    the one already installed from the GitHub release.

Expected behavior

Either the reflection path should be robust across Velocity builds (with a
clear error identifying why the holder is null, e.g. build/version
mismatch), or Connect should document which Velocity builds are supported so
this class of failure is diagnosable without reading the plugin's own
source.

Happy to help

This network's operator is willing to test a patched build, provide more
logs, or answer questions -- this was reproduced consistently and isolated
carefully rather than a one-off report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions