apache/iceberg · error · UnsupportedOperationException

${getClass().getName()} does not implement length

Error message

${getClass().getName()} does not implement length

What it means

FileScopedPositionDeleteWriter wraps per-file position delete writers and delegates length() to the current writer. When no per-file writer is active (or the underlying writer type cannot report length), it throws UnsupportedOperationException with the class name, signaling that length is not available from this writer abstraction.

Source

Thrown at core/src/main/java/org/apache/iceberg/deletes/FileScopedPositionDeleteWriter.java:76

  @Override
  public void write(PositionDelete<T> positionDelete) {
    writer(positionDelete.path()).write(positionDelete);
  }

  private FileWriter<PositionDelete<T>, DeleteWriteResult> writer(CharSequence path) {
    if (currentWriter == null) {
      openCurrentWriter(path);
    } else if (CharSequenceUtil.unequalPaths(currentPath, path)) {
      closeCurrentWriter();
      openCurrentWriter(path);
    }

    return currentWriter;
  }

  @Override
  public long length() {
    throw new UnsupportedOperationException(getClass().getName() + " does not implement length");
  }

  @Override
  public DeleteWriteResult result() {
    Preconditions.checkState(closed, "Cannot get result from unclosed writer");
    return new DeleteWriteResult(deleteFiles, referencedDataFiles);
  }

  @Override
  public void close() throws IOException {
    if (!closed) {
      closeCurrentWriter();
      this.closed = true;
    }
  }

  private void openCurrentWriter(CharSequence path) {
    Preconditions.checkState(!closed, "Writer has already been closed");

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Do not call length() on FileScopedPositionDeleteWriter; obtain sizes from the DeleteWriteResult's deleteFiles after result()
  2. Use a different writer implementation that supports length() if byte-length tracking is required
  3. Report metrics from the wrapped current writer's result files instead of the wrapper
  4. Check whether the code path should be using a fan-out/clustered writer rather than a file-scoped one
Defensive patterns

Strategy: validation

Validate before calling

if (writer instanceof FileScopedPositionDeleteWriter) {
  throw new IllegalArgumentException("length() not supported; read sizes from result delete files");
}

Type guard

boolean supportsLength(LengthReportingWriter w) {
  return !(w instanceof FileScopedPositionDeleteWriter);
}

Try / catch

try {
  long len = writer.length();
} catch (UnsupportedOperationException e) {
  long len = writer.result().deleteFiles().stream().mapToLong(DeleteFile::fileSizeInBytes).sum();
}

Prevention

When it happens

Trigger: Calling length() on a FileScopedPositionDeleteWriter - the class deliberately does not implement it; callers expecting a measurable output stream length (e.g. generic writer metrics code) hit this.

Common situations: Framework code that unconditionally polls writer length for progress reporting or file-size checks; misuse of the file-scoped writer where a rollable/measurable writer (e.g. ClusteredDataWriter-style) was expected.

Related errors


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