apache/beam · error · UnsupportedOperationException
getCoder is called before init
Error message
getCoder is called before init
What it means
SingleStoreDefaultRowMapper.getCoder() returns a RowCoder built from the schema discovered during init(). If init() has not run yet, schema is null and the mapper refuses to return a coder, throwing UnsupportedOperationException. This is a lifecycle guard: the mapper cannot infer a Beam schema before it connects to the database and reads result-set metadata.
Solutions
- Call init(...) on the row mapper before invoking getCoder()
- Ensure you are using SingleStoreIO's standard pipeline construction so the source initializes the mapper automatically
- In tests, set the schema field (or call the init path with a valid statement/connection) before asserting on getCoder()
- Upgrade Beam SingleStore IO if a released version fails to init the mapper before coder resolution (lifecycle bug)
Example fix
// before SingleStoreDefaultRowMapper mapper = new SingleStoreDefaultRowMapper(); SchemaCoder<Row> coder = mapper.getCoder(); // throws // after SingleStoreDefaultRowMapper mapper = new SingleStoreDefaultRowMapper(); mapper.init(statement); // populate schema from ResultSetMetaData SchemaCoder<Row> coder = mapper.getCoder();
Defensive patterns
Strategy: try-catch
Validate before calling
if (mapperHasSchema(mapper)) { coder = mapper.getCoder(); } Type guard
boolean mapperInitialized(SingleStoreDefaultRowMapper m) { try { return m.getCoder() != null; } catch (UnsupportedOperationException e) { return false; } } Try / catch
try { SchemaCoder<Row> coder = mapper.getCoder(); } catch (UnsupportedOperationException e) { throw new IllegalStateException("Row mapper not initialized: call init() before getCoder()", e); } Prevention
- Always construct mappers through SingleStoreIO's pipeline API so init() runs automatically
- Never call getCoder() directly on a mapper you did not init in the same scope
- In tests, use the same init path as production before asserting on coder behavior
When it happens
Trigger: Calling getCoder() on a SingleStoreDefaultRowMapper instance before calling init(). This happens when a SingleStoreIO read is built with a custom row mapper but the mapper is not initialized by the source before coder resolution, or when user code invokes getCoder() directly on a freshly constructed mapper.
Common situations: Supplying SingleStoreIO.read().withRowMapper(new MyMapper()) where the mapper relies on default init order and gets queried early; unit tests instantiating the mapper and calling getCoder() without init(); refactoring that moves coder resolution before source initialization.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot access FinishBundleContext outside of @FinishBundle…
- Cannot access StartBundleContext outside of @StartBundle…
- +fieldType.getTypeName()+ is not supported
- Illegal access to pipeline after visitor traversal was…
- One or more ErrorHandlers aren't closed, and this pipeline…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/c6a07cbf95b6a916.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/singlestore/src/main/java/org/apache/beam/sdk/io/singlestore/SingleStoreDefaultRowMapper.java:113
int fieldCount = schema.getFieldCount();
for (int i = 0; i < fieldCount; i++) {
Object value = converters.get(i).getValue(resultSet, i + 1);
if (resultSet.wasNull() || value == null) {
rowBuilder.addValue(null);
} else {
rowBuilder.addValue(value);
}
}
return rowBuilder.build();
}
@Override
public SchemaCoder<Row> getCoder() throws Exception {
if (schema == null) {
throw new UnsupportedOperationException("getCoder is called before init");
}
return RowCoder.of(this.schema);
}
abstract static class ResultSetFieldConverter implements Serializable {
abstract @Nullable Object getValue(ResultSet rs, Integer index) throws SQLException;
Schema.Field getSchemaField(ResultSetMetaData md, Integer index) throws SQLException {
String label = md.getColumnLabel(index);
return Schema.Field.of(label, getSchemaFieldType(md, index))
.withNullable(md.isNullable(index) == java.sql.ResultSetMetaData.columnNullable);
}
abstract Schema.FieldType getSchemaFieldType(ResultSetMetaData md, Integer index)
throws SQLException;
/**View on GitHub (pinned to 12126d8942)