apache/iceberg · error · RuntimeIOException

RuntimeIOException

Error message

RuntimeIOException

What it means

During BaseRewriteManifests.apply(), entries are appended to new manifest writers on worker threads. Any underlying IOException while writing a manifest is wrapped in RuntimeIOException, which aborts the rewrite with this unchecked exception.

Source

Thrown at core/src/main/java/org/apache/iceberg/BaseRewriteManifests.java:269

              manifest -> {
                if (containsDeletes(manifest) || !matchesPredicate(manifest)) {
                  keptManifests.add(manifest);
                } else {
                  rewrittenManifests.add(manifest);
                  try (ManifestReader<DataFile> reader =
                      ManifestFiles.read(manifest, ops().io(), ops().current().specsById())
                          .select(Collections.singletonList("*"))) {
                    reader
                        .liveEntries()
                        .forEach(
                            entry ->
                                appendEntry(
                                    entry,
                                    clusterByFunc.apply(entry.file()),
                                    manifest.partitionSpecId()));

                  } catch (IOException x) {
                    throw new RuntimeIOException(x);
                  }
                }
              });
    } finally {
      Tasks.foreach(writers.values()).executeWith(workerPool()).run(WriterWrapper::close);
    }
  }

  private boolean containsDeletes(ManifestFile manifest) {
    return manifest.content() == ManifestContent.DELETES;
  }

  private boolean matchesPredicate(ManifestFile manifest) {
    return predicate == null || predicate.test(manifest);
  }

  private void validateDeletedManifests(
      Set<ManifestFile> currentManifests, long currentSnapshotID) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Inspect the cause (getCause()) to find the real IOException and fix storage access (permissions, quota, connectivity).
  2. Retry the rewriteManifests() operation once storage is healthy — the operation is safe to rerun.
  3. Verify the FileIO's warehouse/metadata location is writable and has free space.
  4. Reduce rewrite concurrency (smaller worker pool) if object storage is throttling requests.

Example fix

// handling
try {
  table.rewriteManifests().clusterBy(f -> f.partition()).commit();
} catch (RuntimeIOException e) {
  LOG.error("Manifest rewrite failed: {}", e.getCause(), e);
  // fix storage issue, then retry
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check the metadata location is writable
boolean writable = table.io() instanceof SupportsBulkOperations
    ? canWrite(table.io(), table.location() + "/metadata")
    : true;

Try / catch

try {
  table.rewriteManifests().clusterBy(f -> f.partition()).commit();
} catch (RuntimeIOException e) {
  LOG.error("Manifest write failed: {}", e.getCause(), e);
  // remediate storage (space/permissions/connectivity) and retry
}

Prevention

When it happens

Trigger: An IOException occurs while writing new manifest files during a rewriteManifests() commit — disk full, permission denied, transient metadata-IO failure on the FileIO backend, or a broken connection to object storage.

Common situations: HDFS/S3 outages or throttling during large manifest rewrites; insufficient permissions on the metadata directory; disk-quota exhaustion on the warehouse volume.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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