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

FlinkSink's builder wraps any IOException from TableLoader.loadTable() in an UncheckedIOException when it eagerly loads the Iceberg table during sink operator chaining. This means the underlying table could not be read/initialized from the configured loader (catalog/filesystem access or metadata parsing failed). The chained cause carries the real reason.

Source

Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/sink/FlinkSink.java:443

    }

    private DataStreamSink<Void> chainIcebergOperators() {
      Preconditions.checkArgument(
          inputCreator != null,
          "Please use forRowData() or forMapperOutputType() to initialize the input DataStream.");
      Preconditions.checkNotNull(tableLoader, "Table loader shouldn't be null");

      DataStream<RowData> rowDataInput = inputCreator.apply(uidPrefix);

      if (table == null) {
        if (!tableLoader.isOpen()) {
          tableLoader.open();
        }

        try (TableLoader loader = tableLoader) {
          this.table = loader.loadTable();
        } catch (IOException e) {
          throw new UncheckedIOException(
              "Failed to load iceberg table from table loader: " + tableLoader, e);
        }
      }

      flinkWriteConf = new FlinkWriteConf(table, writeOptions, readableConfig);

      // Find out the equality field id list based on the user-provided equality field column names.
      Set<Integer> equalityFieldIds =
          SinkUtil.checkAndGetEqualityFieldIds(table, equalityFieldColumns);

      RowType flinkRowType =
          resolvedSchema != null
              ? toFlinkRowType(table.schema(), resolvedSchema)
              : toFlinkRowType(table.schema(), tableSchema);
      int writerParallelism =
          flinkWriteConf.writeParallelism() == null
              ? rowDataInput.getParallelism()
              : flinkWriteConf.writeParallelism();

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Run tableLoader.open(); tableLoader.loadTable() standalone before submitting the job to reproduce and see the root-cause exception in the chain
  2. Verify the catalog config (type, URI, warehouse) and credentials used to build the TableLoader
  3. Confirm the table exists: list it via the same catalog (e.g. Spark/iceberg CLI) and check the metadata JSON location is readable from the job's filesystem
  4. If the table was recently dropped/recreated, restart from a fresh savepoint/checkpoint so operator state matches current table state

Example fix

// before
TableLoader loader = TableLoader.fromHadoopTable("hdfs://nn/warehouse/db/wrong_table");
FlinkSink.forRowData(input).tableLoader(loader).append();
// after
TableLoader loader = TableLoader.fromCatalog(
    CatalogLoader.hive("hive", new Configuration(), conf),
    TableIdentifier.of("db", "table"));
// validate eagerly before append
loader.open();
loader.loadTable(); // surfaces errors with full cause before job submission
Defensive patterns

Strategy: validation

Validate before calling

TableLoader loader = TableLoader.fromCatalog(catalogLoader, tableId);
loader.open();
Table t = loader.loadTable(); // throws early with root cause
System.out.println("loaded table: " + t.name());

Type guard

boolean canLoad(TableLoader loader) {
  if (loader == null) return false;
  try (TableLoader l = loader) {
    if (!l.isOpen()) l.open();
    l.loadTable();
    return true;
  } catch (IOException | RuntimeException e) {
    LOG.error("table load failed", e);
    return false;
  }
}

Try / catch

try (TableLoader loader = tableLoader) {
  loader.open();
  loader.loadTable();
} catch (UncheckedIOException e) {
  LOG.error("Cannot load Iceberg table: {}", e.getCause(), e);
  throw new JobSetupException("fix catalog/warehouse/credentials", e);
}

Prevention

When it happens

Trigger: Calling FlinkSink.forRowData(...).tableLoader(loader).append() (chainIcebergOperators) where loadTable() throws IOException: table metadata file missing/corrupt, catalog unreachable, bad credentials, or wrong table identifier.

Common situations: Typo in table identifier (warehouse/database/table), S3/HDFS credentials or endpoint misconfiguration, table dropped/renamed by another job, metadata JSON deleted, or using a TableLoader whose location points to a stale checkpoint path.

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/ce88647eead03a92. Report an issue: GitHub.