apache/iceberg · error · RuntimeIOException

Failed to get stripe information from writer for: %s

Error message

Failed to get stripe information from writer for: %s

What it means

splitOffsets() returns the byte offsets of each ORC stripe for split planning, and it requires the appender to be closed so the stripe list is final. If retrieving stripes from the closed Writer throws an IOException, a RuntimeIOException with the file location is thrown. It also enforces the state precondition that the file has already been closed.

Source

Thrown at orc/src/main/java/org/apache/iceberg/orc/OrcFileAppender.java:149

      throw new UncheckedIOException(
          String.format(
              "Can't get Stripe's length from the file writer with path: %s.", file.location()),
          e);
    }

    // This value is an estimate, not the actual length.
    return (long)
        Math.ceil(dataLength + (estimateMemory + (long) batch.size * avgRowByteSize) * 0.2);
  }

  @Override
  public List<Long> splitOffsets() {
    Preconditions.checkState(isClosed, "File is not yet closed");
    try {
      List<StripeInformation> stripes = writer.getStripes();
      return Collections.unmodifiableList(Lists.transform(stripes, StripeInformation::getOffset));
    } catch (IOException e) {
      throw new RuntimeIOException(
          e, "Failed to get stripe information from writer for: %s", file.location());
    }
  }

  @Override
  public void close() throws IOException {
    if (!isClosed) {
      try {
        if (batch.size > 0) {
          writer.addRowBatch(batch);
          batch.reset();
        }
      } finally {
        writer.close();
        this.isClosed = true;
      }
    }
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Always close() the appender fully and successfully before calling splitOffsets().
  2. Inspect the wrapped IOException cause if getStripes fails after close; re-run the write task so the file is rewritten cleanly.
  3. Guard framework glue code so splitOffsets is only invoked in the commit phase after successful close.

Example fix

// before
List<Long> offsets = appender.splitOffsets(); // IllegalStateException / RuntimeIOException
appender.close();

// after
appender.close();
List<Long> offsets = appender.splitOffsets(); // only after successful close
Defensive patterns

Strategy: validation

Validate before calling

if (!appender.isClosed()) {
  throw new IllegalStateException("Call close() before splitOffsets()");
}

Try / catch

try {
  List<Long> offsets = appender.splitOffsets();
} catch (RuntimeIOException | IllegalStateException e) {
  LOG.error("splitOffsets failed: {}", e.getMessage());
  throw e;
}

Prevention

When it happens

Trigger: Calling appender.splitOffsets() before close() (IllegalStateException 'File is not yet closed'), or after close() when writer.getStripes() throws IOException due to storage/backend problems reading stripe metadata.

Common situations: Commit-time split-offset collection racing with or preceding appender close; storage backend errors when finalizing ORC files on S3/HDFS; framework code calling splitOffsets on an appender whose close failed midway.

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


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