apache/iceberg · error · UnsupportedOperationException

WriterSink is used only for writing; committing is handled b

Error message

WriterSink is used only for writing; committing is handled by the main sink

What it means

DynamicIcebergSink's WriterSink is a write-only topology; committing is performed by a separate main sink operator. Its createCommitter always throws UnsupportedOperationException because a committer is intentionally not provided for the writer sub-job.

Source

Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/sink/dynamic/DynamicIcebergSink.java:219

      this.flinkConfig = flinkConfig;
      this.cacheMaximumSize = cacheMaximumSize;
    }

    @Override
    public SinkWriter<DynamicRecordInternal> createWriter(WriterInitContext context) {
      return new DynamicWriter(
          catalogLoader.loadCatalog(),
          writeProperties,
          flinkConfig,
          cacheMaximumSize,
          new DynamicWriterMetrics(context.metricGroup()),
          context.getTaskInfo().getIndexOfThisSubtask(),
          context.getTaskInfo().getAttemptNumber());
    }

    @Override
    public Committer<DynamicWriteResult> createCommitter(CommitterInitContext context) {
      throw new UnsupportedOperationException(
          "WriterSink is used only for writing; committing is handled by the main sink");
    }

    @Override
    public SimpleVersionedSerializer<DynamicWriteResult> getCommittableSerializer() {
      return new DynamicWriteResultSerializer();
    }
  }

  public static class Builder<T> {
    private DataStream<T> input;
    private DynamicRecordGenerator<T> generator;
    private CatalogLoader catalogLoader;
    private String uidPrefix = null;
    private final Map<String, String> writeOptions = Maps.newHashMap();
    private final Map<String, String> snapshotSummary = Maps.newHashMap();
    private ReadableConfig readableConfig = new Configuration();
    private TableCreator tableCreator = TableCreator.DEFAULT;

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use the main DynamicIcebergSink's committer path for committing; do not wire the WriterSink as a committing sink.
  2. If integrating programmatically, only invoke createCommitter on the committer sink's provider, not the writer's.
  3. Guard custom code with a check of which sink branch is being configured before requesting a committer.
Defensive patterns

Strategy: validation

Validate before calling

if (sinkProvider instanceof WriterSinkProvider) { throw new IllegalStateException("WriterSink cannot commit; use the main sink's committer"); }

Try / catch

try { provider.createCommitter(ctx); } catch (UnsupportedOperationException e) { /* route to the main DynamicIcebergSink committer instead */ }

Prevention

When it happens

Trigger: Calling createCommitter on the writer sink's sink provider — e.g. misconfiguring the sink so Flink tries to instantiate a committer for the WriterSink branch, or calling the method directly in custom code.

Common situations: Custom sink topology wiring that expects the writer to also commit; framework changes that probe createCommitter unconditionally.

Related errors


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