apache/beam · error · java.lang.IllegalArgumentException
DynamicMessage is not supported by the ProtoCoder, use the…
Error message
DynamicMessage is not supported by the ProtoCoder, use the DynamicProtoCoder.
What it means
ProtoCoder requires a concrete protobuf-generated Message class so it can obtain a Parser via getDefaultInstance(). DynamicMessage has no such static factory and needs a Descriptor, so ProtoCoder deliberately rejects it and directs users to DynamicProtoCoder.
Solutions
- Use DynamicProtoCoder instead of ProtoCoder for DynamicMessage types.
- If the type is known at compile time, use the generated message class with ProtoCoder.of(GeneratedMessage.class).
- If relying on automatic coder inference, ensure the PCollection's TypeDescriptor points at the concrete generated class.
Example fix
// before ProtoCoder<DynamicMessage> coder = ProtoCoder.of(DynamicMessage.class); // after DynamicProtoCoder<DynamicMessage> coder = DynamicProtoCoder.of(descriptor);
Defensive patterns
Strategy: type-guard
Validate before calling
if (DynamicMessage.class.equals(type.getRawType())) {
throw new IllegalArgumentException("use DynamicProtoCoder");
} Type guard
boolean isDynamic = msg instanceof DynamicMessage; // route to DynamicProtoCoder if true
Try / catch
try { coder = ProtoCoder.of(clazz); } catch (IllegalArgumentException e) { coder = DynamicProtoCoder.of(descriptor); } Prevention
- Use DynamicProtoCoder for descriptor-based messages.
- Keep TypeDescriptors pointing at concrete generated classes.
- Check coder type before applying schema conversions.
When it happens
Trigger: Creating ProtoCoder.of(DynamicMessage.class) (or a coderFor/type inference resolving to DynamicMessage) and then decoding, or any path that calls getParser() with protoMessageClass == DynamicMessage.
Common situations: Working with dynamically parsed protos (e.g. from descriptors read at runtime) but picking the wrong coder class; copying coder code from examples that used DynamicMessage with parseFrom.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Protocol Buffers message
- Aliased enumerations not currently supported.
- Any not yet supported
- ApproximateUnique.PerKey requires its input to use KvCoder
- AvroCoder for GenericRecord requires a schema
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/8bc8c230df012607.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoCoder.java:302
*/
final Set<Class<?>> extensionHostClasses;
// Transient fields that are lazy initialized and then memoized.
private transient volatile ExtensionRegistry memoizedExtensionRegistry;
transient Parser<T> memoizedParser;
/** Private constructor. */
protected ProtoCoder(Class<T> protoMessageClass, Set<Class<?>> extensionHostClasses) {
this.protoMessageClass = protoMessageClass;
this.extensionHostClasses = extensionHostClasses;
}
/** Get the memoized {@link Parser}, possibly initializing it lazily. */
protected synchronized Parser<T> getParser() {
if (memoizedParser == null) {
try {
if (DynamicMessage.class.equals(protoMessageClass)) {
throw new IllegalArgumentException(
"DynamicMessage is not supported by the ProtoCoder, use the DynamicProtoCoder.");
} else {
@SuppressWarnings("unchecked")
T protoMessageInstance =
(T) protoMessageClass.getMethod("getDefaultInstance").invoke(null);
@SuppressWarnings("unchecked")
Parser<T> tParser = (Parser<T>) protoMessageInstance.getParserForType();
memoizedParser = tParser;
}
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new IllegalArgumentException(e);
}
}
return memoizedParser;
}
/**
* Returns a {@link CoderProvider} which uses the {@link ProtoCoder} for {@link Message protoView on GitHub (pinned to 12126d8942)