Symptom

MQTT publish and subscribe both fail on the deployed server (/usr/local/bin/krill.jar) with IllegalArgumentException: no NetworkModule installed for scheme "tcp". Works fine during ./gradlew :server:run (not minimized).

Root cause

shadowJar’s minimize {} block prunes classes that aren’t statically reachable from the entry point. Paho’s transport factories — TCPNetworkModuleFactory, SSLNetworkModuleFactory, WebSocketNetworkModuleFactory, WebSocketSecureNetworkModuleFactory — are only referenced via ServiceLoader (the META-INF/services file), never by a static import. Minimize removes the class files but leaves the service descriptor intact. In Java 21, ServiceLoader silently skips entries whose classes fail to load, leaving the iterator empty. NetworkModuleService.validateURI() iterates the empty loader and throws the error. The MQTT node is completely dead on every deployed server.

The filed diagnosis (TCCL on coroutine worker threads) was incorrect: Paho 1.2.5’s static initializer explicitly passes NetworkModuleService.class.getClassLoader() to ServiceLoader.load(), not Thread.currentThread().contextClassLoader.

Fix

Prevention