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

  1. Eagerly call loader.open(); loader.loadTable() in your job setup to surface the root cause before submission
  2. Verify catalog configuration (type/uri/warehouse) and that the identifier resolves (list tables in the catalog)
  3. Check filesystem credentials (S3/HDFS/GCS) are present in the Flink configuration on JM and TMs
  4. 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

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


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