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).
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.
exclude(dependency("org.eclipse.paho:.*:.*")) to minimize {} in server/build.gradle.kts, following the same pattern already used for gRPC, Netty, H2, and Exposed.requiredClasses in the doLast shadowJar verification block so future minimize regressions fail the build rather than ship silently.requiredServiceEntries for the same reason.META-INF/services (no static import) must be excluded from minimize {}. If the code compiles and tests pass but a certain feature is dead on the deployed JAR, check whether minimize pruned its ServiceLoader-only classes.doLast integrity check in the shadowJar task is the regression guard — keep it in sync whenever a new minimize-exempt dependency is added or a new ServiceLoader-based feature ships.