apache/iceberg · error · java.lang.RuntimeException

Failed to instantiate DynamicRecordGeneratorSQL %s

Error message

Failed to instantiate DynamicRecordGeneratorSQL %s

What it means

After the interface check, IcebergTableSink instantiates the configured DynamicRecordGeneratorSQL reflectively via a compatible constructor; any failure (no matching ctor, reflective invocation exception, classloading errors) is wrapped in this RuntimeException naming the class.

Source

Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/IcebergTableSink.java:296

  private DynamicTableRecordGenerator createDynamicRecordGenerator(String generatorImpl) {
    RowType rowType = (RowType) resolvedSchema.toSourceRowDataType().getLogicalType();

    DynConstructors.Ctor<DynamicTableRecordGenerator> ctor;

    try {
      ctor =
          DynConstructors.builder(DynamicTableRecordGenerator.class)
              .loader(IcebergTableSink.class.getClassLoader())
              .impl(generatorImpl, RowType.class)
              .impl(generatorImpl, RowType.class, Map.class, Configuration.class)
              .buildChecked();
      return ctor.newInstance(rowType, writeProps, fromReadableConfig());
    } catch (ClassCastException e) {
      throw new IllegalArgumentException(
          String.format("Class %s does not implement DynamicRecordGeneratorSQL", generatorImpl), e);
    } catch (Exception e) {
      throw new RuntimeException(
          String.format("Failed to instantiate DynamicRecordGeneratorSQL %s", generatorImpl), e);
    }
  }

  private Configuration fromReadableConfig() {
    return readableConfig instanceof Configuration
        ? (Configuration) readableConfig
        : Configuration.fromMap(readableConfig.toMap());
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Add public constructors matching (RowType) and (RowType, Map<String,String>, Configuration) to the generator class
  2. Inspect the cause chain of the RuntimeException to find the real construction failure and fix it (config value, dependency)
  3. Ensure the generator jar is on the Flink job classpath and built against the same Iceberg/Flink versions

Example fix

// before
class MyGen implements DynamicRecordGeneratorSQL { MyGen(){} } // no matching ctor
// after
class MyGen implements DynamicRecordGeneratorSQL {
  public MyGen(RowType rowType) {...}
  public MyGen(RowType rowType, Map<String,String> props, Configuration conf) {...}
}
Defensive patterns

Strategy: try-catch

Validate before calling

for (Constructor<?> ctor : Class.forName(generatorImpl).getConstructors()) {
  // require (RowType) or (RowType, Map, Configuration)
}

Try / catch

try {
  generator = sink.createDynamicRecordGenerator(rowType);
} catch (RuntimeException e) {
  LOG.error("Failed to instantiate generator {} — check constructor signature and cause", generatorImpl, e.getCause());
  throw e;
}

Prevention

When it happens

Trigger: Configured generator class implements the interface but lacks a (RowType) or (RowType, Map, Configuration) constructor, its constructor throws, or the class cannot be loaded from the sink's classloader.

Common situations: Generator written for a different Iceberg version's constructor signature; constructor throwing during initialization (bad config parsing); shaded/missing dependencies inside the generator class.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/44ae6b101a9db4b5. Report an issue: GitHub.