Protobuf class conflict: pekko-connectors-google-cloud-pub-sub-grpc bundles unshaded protobuf-java classes
`pekko-connectors-google-cloud-pub-sub-grpc:1.2.0` bundles unshaded `com.google.protobuf.*` classes inside its JAR.
These conflict with `protobuf-java:4.33.2` at runtime, causing `ExceptionInInitializerError` when the JVM classloader picks up the **bundled (older) classes** first.
## Environment
- pekko-connectors-google-cloud-pub-sub-grpc: **1.2.0**
- protobuf-java (project dependency): **4.33.2**
- JVM: 21
- Runtime: Google Cloud Run
## Problem
The pekko-connectors JAR contains 728 unshaded `com.google.protobuf.*` classes. When these are loaded before `protobuf-java:4.33.2`, the `DescriptorProtos$Edition` enum only defines values up to `EDITION_2023`. However, `protobuf-java:4.33.2` includes `JavaEditionDefaults` binary data referencing `maximum_edition=1001 (EDITION_2024)`.
This causes the following failure chain:
1. Any Google Cloud client library call (e.g. `CloudTasksClient`, `PubSubClient`) triggers protobuf descriptor initialization
2. `TargetProto.<clinit>` → `Descriptors.getJavaEditionDefaults()`
3. `EDITION_2024 (1001)` is unknown in the bundled enum → `getMaximumEdition()` returns `EDITION_UNKNOWN (0)`
4. `IllegalArgumentException` → `ExceptionInInitializerError` (extends `LinkageError`)
5. Pekko treats `LinkageError` as fatal → `System.exit()`
## Steps to Reproduce
1. Add `pekko-connectors-google-cloud-pub-sub-grpc:1.2.0` and any Google Cloud client library that depends on `protobuf-java:4.x` (e.g. `google-cloud-tasks:2.85.0`)
2. Call any method that triggers protobuf descriptor initialization (e.g. `com.google.cloud.tasks.v2.TargetProto.getDescriptor`)
3. Observe `ExceptionInInitializerError`
```scala
// In sbt console:
scala> com.google.cloud.tasks.v2.TargetProto.getDescriptor
// java.lang.ExceptionInInitializerError
// at com.google.cloud.tasks.v2.TargetProto.<clinit>
// Caused by: java.lang.IllegalArgumentException
```
## Why `exclude` in build tools does not work
The 728 `com.google.protobuf.*` classes are **physically embedded inside the pekko-connectors JAR itself** — they are not pulled in as a transitive dependency. Therefore:
- `exclude("com.google.protobuf", "protobuf-java")` in sbt/Maven/Gradle has **no effect** — it only controls dependency resolution, not classes already packaged in the JAR
- `dependencyOverrides` also has **no effect** — both JARs end up on the classpath, and the JVM loads whichever it finds first
```bash
# Verification: 728 unshaded protobuf classes inside the JAR
$ jar tf pekko-connectors-google-cloud-pub-sub-grpc_2.13-1.2.0.jar | grep "com/google/protobuf" | wc -l
728
```
## Current Workaround
We strip the embedded protobuf classes from the JAR during Docker image build:
```dockerfile
RUN for jar in foo-bar-latest/lib/*pekko-connectors-google-cloud-pub-sub-grpc*; do \
zip -d "$jar" "com/google/protobuf/*" || true; \
done
```
This forces the JVM to load protobuf classes exclusively from `protobuf-java-4.33.2.jar`.
## Suggested Fix
One of the following:
1. **Stop bundling protobuf classes** in the pekko-connectors JAR and declare `protobuf-java` as a normal transitive dependency
2. **Shade (relocate)** the bundled protobuf classes to a different package (e.g. `org.apache.pekko.shaded.com.google.protobuf`)
3. **Upgrade** the bundled protobuf classes to be compatible with protobuf-java 4.x (`EDITION_2024`)
关闭于 2026-02-27 5 条评论