Module fails to load with NoClassDefFoundError, but works locally

My Ignition Module uses gRPC to send requests to an external server. In my gateway's build.gradle.kts I add the gRPC dependencies for version 1.70.0

dependencies {
    // Ignition dependencies
    implementation("com.inductiveautomation.ignitionsdk:ignition-common:${rootProject.extra["sdk_version"]}")
    implementation("com.inductiveautomation.ignitionsdk:gateway-api:${rootProject.extra["sdk_version"]}")
    compileOnly(project(":common"))

    // gRPC and Proto
    runtimeOnly("io.grpc:grpc-netty-shaded:$grpcVersion")
    api("com.google.protobuf:protobuf-java:$protobufVersion")
    api("io.grpc:grpc-protobuf:$grpcVersion")
    api("io.grpc:grpc-stub:$grpcVersion")
    api("io.grpc:grpc-core:$grpcVersion")
    api("io.grpc:grpc-api:$grpcVersion")
    compileOnly("org.apache.tomcat:annotations-api:6.0.53") // necessary for Java 9+

    testImplementation("io.grpc:grpc-testing:$grpcVersion")
    testImplementation("io.grpc:grpc-inprocess:$grpcVersion")
}

I initialize the gRPC service's ManagedChannel in the GatewayHook's startup.

I can build locally and run tests, but when I upload the .modl file I immediately get a fault with NoClassDefFoundError on the grpc code.

java.lang.Exception: Exception while starting up module "com.company.moduleName"
Caused by: java.lang.NoClassDefFoundError: io/grpc/StatusRuntimeException
Caused by: java.lang.ClassNotFoundException: io.grpc.StatusRuntimeException

As far as I can tell the jars are being built correctly.
./gradlew gateway:dependencies --configuration runtimeClasspath shows all the dependencies I'd expect.

I added a Main.java class and ran the code locally, and can successfully execute the gRPC requests.

Am I doing something wrong in the module build? Are the dependencies not being packaged correctly into the .modl? Or is it because something isn't loaded yet in startup? I'm fairly new to gradle, so I may have missed something obvious.

Using java17 and building for ignition 8.1.

Unzip the module and take a look for yourself. The .modl file is just a zip file.

Also, if you're using the Ignition gradle plugin, I think the dependencies you want packaged into the module need to be declared with the modl* dependency syntax, e.g.

    modlApi("com.google.protobuf:protobuf-java:$protobufVersion")
    modlApi("io.grpc:grpc-protobuf:$grpcVersion")

Yup, that did it.

Thank you! I was losing it trying to figure out why the dependency isn't found.