{"record":{"id":"ce88647eead03a92","repo":"apache/iceberg","slug":"failed-to-load-iceberg-table-from-table-loader","errorCode":null,"errorMessage":"Failed to load iceberg table from table loader: ${tableLoader}","messagePattern":"Failed to load iceberg table from table loader: (.+?)","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"critical","filePath":"flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/sink/FlinkSink.java","lineNumber":443,"sourceCode":"    }\n\n    private DataStreamSink<Void> chainIcebergOperators() {\n      Preconditions.checkArgument(\n          inputCreator != null,\n          \"Please use forRowData() or forMapperOutputType() to initialize the input DataStream.\");\n      Preconditions.checkNotNull(tableLoader, \"Table loader shouldn't be null\");\n\n      DataStream<RowData> rowDataInput = inputCreator.apply(uidPrefix);\n\n      if (table == null) {\n        if (!tableLoader.isOpen()) {\n          tableLoader.open();\n        }\n\n        try (TableLoader loader = tableLoader) {\n          this.table = loader.loadTable();\n        } catch (IOException e) {\n          throw new UncheckedIOException(\n              \"Failed to load iceberg table from table loader: \" + tableLoader, e);\n        }\n      }\n\n      flinkWriteConf = new FlinkWriteConf(table, writeOptions, readableConfig);\n\n      // Find out the equality field id list based on the user-provided equality field column names.\n      Set<Integer> equalityFieldIds =\n          SinkUtil.checkAndGetEqualityFieldIds(table, equalityFieldColumns);\n\n      RowType flinkRowType =\n          resolvedSchema != null\n              ? toFlinkRowType(table.schema(), resolvedSchema)\n              : toFlinkRowType(table.schema(), tableSchema);\n      int writerParallelism =\n          flinkWriteConf.writeParallelism() == null\n              ? rowDataInput.getParallelism()\n              : flinkWriteConf.writeParallelism();","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/sink/FlinkSink.java#L425-L461","documentation":"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.","triggerScenarios":"Calling FlinkSink.forRowData(...).tableLoader(loader).append() (chainIcebergOperators) where loadTable() throws IOException: table metadata file missing/corrupt, catalog unreachable, bad credentials, or wrong table identifier.","commonSituations":"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.","solutions":["Run tableLoader.open(); tableLoader.loadTable() standalone before submitting the job to reproduce and see the root-cause exception in the chain","Verify the catalog config (type, URI, warehouse) and credentials used to build the TableLoader","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","If the table was recently dropped/recreated, restart from a fresh savepoint/checkpoint so operator state matches current table state"],"exampleFix":"// before\nTableLoader loader = TableLoader.fromHadoopTable(\"hdfs://nn/warehouse/db/wrong_table\");\nFlinkSink.forRowData(input).tableLoader(loader).append();\n// after\nTableLoader loader = TableLoader.fromCatalog(\n    CatalogLoader.hive(\"hive\", new Configuration(), conf),\n    TableIdentifier.of(\"db\", \"table\"));\n// validate eagerly before append\nloader.open();\nloader.loadTable(); // surfaces errors with full cause before job submission","handlingStrategy":"validation","validationCode":"TableLoader loader = TableLoader.fromCatalog(catalogLoader, tableId);\nloader.open();\nTable t = loader.loadTable(); // throws early with root cause\nSystem.out.println(\"loaded table: \" + t.name());","typeGuard":"boolean canLoad(TableLoader loader) {\n  if (loader == null) return false;\n  try (TableLoader l = loader) {\n    if (!l.isOpen()) l.open();\n    l.loadTable();\n    return true;\n  } catch (IOException | RuntimeException e) {\n    LOG.error(\"table load failed\", e);\n    return false;\n  }\n}","tryCatchPattern":"try (TableLoader loader = tableLoader) {\n  loader.open();\n  loader.loadTable();\n} catch (UncheckedIOException e) {\n  LOG.error(\"Cannot load Iceberg table: {}\", e.getCause(), e);\n  throw new JobSetupException(\"fix catalog/warehouse/credentials\", e);\n}","preventionTips":["Eagerly load the table in job setup before FlinkSink.append() so failures happen before submission","Verify table identifiers against the catalog (list tables) instead of hardcoding paths","Keep catalog credentials and warehouse config validated in CI with a smoke loadTable() call","Avoid pointing TableLoader at raw locations of dropped/recreated tables"],"tags":["flink","table-loader","io","iceberg"],"backgroundTag":"file-read-failed","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}