apache/iceberg · error · UncheckedIOException
Failed to create tableMaintenance
Error message
Failed to create tableMaintenance
What it means
IcebergSink.addPostCommitTopology wraps IOException from building the table maintenance (compaction/expire/orphan-cleanup) topology and rethrows it as UncheckedIOException. It means the sink could not append the maintenance operators to the job graph, typically because the underlying catalog/table operations failed with IO problems.
Source
Thrown at flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/sink/IcebergSink.java:305
} else {
builder = TableMaintenance.forChangeStream(tableChangeStream, tableLoader);
}
builder
.uidSuffix(tableMaintenanceUid)
.add(maintenanceTasks)
.rateLimit(Duration.ofSeconds(flinkMaintenanceConfig.rateLimit()))
.lockCheckDelay(Duration.ofSeconds(flinkMaintenanceConfig.lockCheckDelay()))
.parallelism(flinkMaintenanceConfig.parallelism());
String slotSharingGroup = flinkMaintenanceConfig.slotSharingGroup();
if (slotSharingGroup != null) {
builder.slotSharingGroup(slotSharingGroup);
}
builder.append();
} catch (IOException e) {
throw new UncheckedIOException("Failed to create tableMaintenance ", e);
}
}
@Override
public DataStream<RowData> addPreWriteTopology(DataStream<RowData> inputDataStream) {
return distributeDataStream(inputDataStream);
}
@Override
public DataStream<CommittableMessage<IcebergCommittable>> addPreCommitTopology(
DataStream<CommittableMessage<WriteResult>> writeResults) {
TypeInformation<CommittableMessage<IcebergCommittable>> typeInformation =
CommittableMessageTypeInfo.of(this::getCommittableSerializer);
String suffix = defaultSuffix(uidSuffix, table.name());
String preCommitAggregatorUid = String.format("Sink pre-commit aggregator: %s", suffix);
// global forces all output records send to subtask 0 of the downstream committer operator.View on GitHub (pinned to 86d9c8fc54)
Solutions
- Verify the catalog and filesystem are reachable and credentials are valid before submitting the Flink job
- Confirm the table still exists at the loader's location and the table loader configuration is correct
- Inspect the wrapped IOException cause for the concrete storage/catalog failure and fix that root cause
- Disable or reconfigure table maintenance (maintenance settings) if it is not needed for this sink
Defensive patterns
Strategy: try-catch
Validate before calling
Table t;
try (TableLoader loader = tableLoader) {
loader.open();
t = loader.loadTable(); // fail fast before building the sink
} Try / catch
try {
sinkBuilder.append();
} catch (UncheckedIOException e) {
Throwable root = ExceptionUtils.getRootCause(e);
LOG.error("table maintenance topology failed: {}", root.getMessage(), root);
throw e;
} Prevention
- Pre-flight check catalog/filesystem connectivity before submitting the Flink job
- Refresh credentials (e.g. S3 session tokens) for long-lived clusters before job restarts
- Confirm the table still exists right before deployment
When it happens
Trigger: Calling IcebergSink builder with maintenance enabled (tableLoader-based catalogs) where TableMaintenance's internal catalog/table access throws IOException while appending the topology via builder.append().
Common situations: Catalog storage (HDFS/S3) unavailable or misconfigured when the sink starts; credentials expired so metadata files can't be read; table deleted/moved between sink construction and topology build.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to create tableMaintenance
- Failed to create tableMaintenance
- Failed to load iceberg table from table loader:
- Failed to load iceberg table from table loader: ${tableLoade
- Failed to create tableMaintenance
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/50942cbb38b2e73e.
Report an issue: GitHub.