apache/iceberg · critical · UncheckedIOException
Failed to load iceberg table from table loader: ${tableLoade
Error message
Failed to load iceberg table from table loader: ${tableLoader} What it means
IcebergSink's checkAndGetTable wraps any IOException from loader.loadTable() in an UncheckedIOException 'Failed to load iceberg table from table loader' when the Table argument is null and the table must be loaded from the TableLoader. It signals the Iceberg table could not be read from the catalog/filesystem at sink construction time; the cause holds the actual error.
Source
Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/sink/IcebergSink.java:919
}
private static String defaultSuffix(String uidSuffix, String defaultSuffix) {
if (uidSuffix == null || uidSuffix.isEmpty()) {
return defaultSuffix;
}
return uidSuffix;
}
private static SerializableTable checkAndGetTable(TableLoader tableLoader, Table table) {
if (table == null) {
if (!tableLoader.isOpen()) {
tableLoader.open();
}
try (TableLoader loader = tableLoader) {
return (SerializableTable) SerializableTable.copyOf(loader.loadTable());
} catch (IOException e) {
throw new UncheckedIOException(
"Failed to load iceberg table from table loader: " + tableLoader, e);
}
}
return (SerializableTable) SerializableTable.copyOf(table);
}
/**
* Clean up after removing {@link Builder#tableSchema}
*
* @deprecated since 1.10.0, will be removed in 2.0.0. Use {@link #toFlinkRowType(Schema,
* ResolvedSchema)} instead.
*/
@Deprecated
private static RowType toFlinkRowType(Schema schema, TableSchema requestedSchema) {
if (requestedSchema != null) {
// Convert the flink schema to iceberg schema firstly, then reassign ids to match the existing
// iceberg schema.View on GitHub (pinned to 86d9c8fc54)
Solutions
- Eagerly call loader.open(); loader.loadTable() in your job setup to surface the root cause before submission
- Verify catalog configuration (type/uri/warehouse) and that the identifier resolves (list tables in the catalog)
- Check filesystem credentials (S3/HDFS/GCS) are present in the Flink configuration on JM and TMs
- If the table was dropped/recreated, point the loader at the correct identifier or resubmit without stale state
Example fix
// before
IcebergSink.forRowData(input)
.tableLoader(TableLoader.fromCatalog(catalogLoader, TableIdentifier.of("db","missing")))
.append();
// after
TableIdentifier id = TableIdentifier.of("db", "table");
CatalogLoader cl = CatalogLoader.hive("hive", conf, hiveConf);
Table t = cl.loadCatalog().loadTable(id); // fail fast with clear cause
IcebergSink.forRowData(input)
.tableLoader(TableLoader.fromCatalog(cl, id))
.table(t) // or rely on validated loader
.append(); Defensive patterns
Strategy: validation
Validate before calling
TableLoader loader = ...;
loader.open();
Table t = loader.loadTable(); // fail fast before job submission
LOG.info("sink table {} spec {}", t.name(), t.spec()); Type guard
boolean tableLoadable(TableLoader loader) {
try (TableLoader l = loader) {
if (!l.isOpen()) l.open();
return l.loadTable() != null;
} catch (Exception e) {
LOG.error("table load failed: {}", e.toString());
return false;
}
} Try / catch
try {
sinkBuilder.append();
} catch (UncheckedIOException e) {
LOG.error("table load failed, cause: {}", e.getCause(), e);
throw new IllegalStateException("verify catalog config/credentials and table existence", e);
} Prevention
- Prefer catalog-based TableLoader (fromCatalog) over location-based loaders
- Validate credentials for the storage backend on JM and TMs before launching
- Check table existence/permissions with an independent catalog client
- When passing an explicit Table to IcebergSink, loaders are bypassed — prefer that in tests
When it happens
Trigger: Constructing IcebergSink (or FlinkSink.invoke via the write builder) without passing a Table and with a TableLoader that fails to loadTable(): nonexistent table, catalog auth failure, unreachable warehouse, corrupt metadata JSON.
Common situations: Hive catalog kerberos/token expiry, wrong warehouse path in catalog config, S3 credentials absent on the job manager, table deleted between job planning and submission, or a TableLoader pointing at a location string instead of a registered catalog table.
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 load iceberg table from table loader: ${tableLoade
- Failed to load iceberg table from table loader:
- Failed to load iceberg table from table loader: ${tableLoade
- Failed to list partitions of table %s
- Failed to create tableMaintenance
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/3866511b82390291.
Report an issue: GitHub.