apache/iceberg · error · 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 Builder builds the sink by loading the Table via the supplied TableLoader and wrapping it as a SerializableTable. If loadTable() throws IOException — missing/unreadable metadata, unreachable filesystem, or bad credentials — it is rethrown as this UncheckedIOException naming the loader. This happens eagerly at builder time (unlike error 1505, which occurs at operator init).

Source

Thrown at flink/v2.1/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. Confirm the TableLoader points to an existing table (verify via the catalog before building the sink).
  2. Ensure Hadoop/cloud configuration and credentials are on the classpath and valid in the submission environment.
  3. Fix the metadata location/warehouse path in the loader configuration.
  4. If the table was recreated, rebuild the sink with a fresh loader rather than reusing a stale one.

Example fix

// before
TableLoader loader = TableLoader.fromCatalog(CatalogLoader.hadoop("hcat", conf, "file:/bad/path"), TableIdentifier.of("db", "t"));
// after
TableLoader loader = TableLoader.fromCatalog(CatalogLoader.hadoop("hcat", conf, warehousePath), TableIdentifier.of("db", "t"));
Defensive patterns

Strategy: try-catch

Validate before calling

try (TableLoader loader = tableLoader) {
  loader.open();
  Table t = loader.loadTable();
  Preconditions.checkArgument(t != null, "Table must load before building IcebergSink");
}

Try / catch

try { buildIcebergSink(); } catch (UncheckedIOException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Failed to load iceberg table")) {
    LOG.error("TableLoader could not load the table; check catalog config and metadata location", e);
  }
}

Prevention

When it happens

Trigger: Calling IcebergSink.builder().tableLoader(loader)...append() where loader.open()/loadTable() raises IOException: wrong metadata location, table dropped/renamed, TaskManager/client lacking Hadoop or cloud credentials, network partition to HDFS/S3.

Common situations: Pointing the loader at a path that no longer exists after table recreation; submitting jobs from an environment without core-site/hive-site conf; expired S3 tokens; catalog URI misconfiguration in Flink SQL or DataStream API code.

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