apache/iceberg · warning

Exception planning scan for

Error message

Exception planning scan for {} at {}

What it means

A WARN log emitted when the MetadataTablePlanner operator fails to plan a scan over a metadata table (e.g. all_manifests, all_data_files) used by the orphan-file/rewrite task. After refreshing the table, split planning via FlinkSplitPlanner threw; the exception is sent to the DeleteOrphanFiles ERROR_STREAM and the errorCounter is incremented, so the task can be marked failed downstream.

Solutions

  1. Check the underlying exception in the side output for unsupported-format or corrupt-file clues; upgrade the Iceberg runtime if the table uses a newer format version.
  2. Verify all manifests/metadata files are readable with the job's credentials; repair with orphan cleanup or restore metadata if corrupted.
  3. Avoid running concurrent expire/orphan jobs that delete metadata while the planner reads it.
  4. Rerun the maintenance task — planning is retryable once the transient I/O issue clears.

Example fix

// before: plan directly against possibly-stale concurrent state
table.refresh();
planIcebergSourceSplits(table, scanContext, workerPool);
// after: serialize maintenance runs / pin snapshot before planning
Table stable = table;
stable.refresh();
scanContext = scanContext.useSnapshot(stable.currentSnapshot().snapshotId());
Defensive patterns

Strategy: retry

Validate before calling

// refresh and confirm the table is readable before planning
table.refresh();
if (table.currentSnapshot() == null && table.schema().columns().isEmpty()) {
  throw new IllegalStateException("Table metadata unreadable, aborting scan planning");
}

Type guard

boolean plannable(Table table) {
  try { table.refresh(); return table.operations().current() != null; }
  catch (RuntimeException e) { return false; }
}

Try / catch

try {
  FlinkSplitPlanner.planIcebergSourceSplits(table, scanContext, workerPool);
} catch (Exception e) {
  ctx.output(DeleteOrphanFiles.ERROR_STREAM, e);
  errorCounter.inc();
}

Prevention

When it happens

Trigger: processElement(): table.refresh() or FlinkSplitPlanner.planIcebergSourceSplits(table, scanContext, workerPool) throws — schema/format incompatibility, corrupt metadata, planning-time I/O reading manifests, or worker-pool issues.

Common situations: Reading metadata of a table written by a newer Iceberg version (unsupported spec/manifest format); corrupt or truncated manifest/metadata files; S3/HDFS read errors while opening manifests; table concurrently expiring snapshots so metadata disappears mid-plan.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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

Appendix: source

Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/operator/MetadataTablePlanner.java:101

        ThreadPools.newFixedThreadPool(table.name() + "-table-planner", workerPoolSize);
    this.splitSerializer = new IcebergSourceSplitSerializer(scanContext.caseSensitive());
    this.errorCounter =
        TableMaintenanceMetrics.groupFor(
                getRuntimeContext(), originalTable.name(), taskName, taskIndex)
            .counter(TableMaintenanceMetrics.ERROR_COUNTER);
  }

  @Override
  public void processElement(Trigger trigger, Context ctx, Collector<SplitInfo> out)
      throws Exception {
    try {
      table.refresh();
      for (IcebergSourceSplit split :
          FlinkSplitPlanner.planIcebergSourceSplits(table, scanContext, workerPool)) {
        out.collect(new SplitInfo(splitSerializer.getVersion(), splitSerializer.serialize(split)));
      }
    } catch (Exception e) {
      LOG.warn("Exception planning scan for {} at {}", table, ctx.timestamp(), e);
      ctx.output(DeleteOrphanFiles.ERROR_STREAM, e);
      errorCounter.inc();
    }
  }

  @Override
  public void close() throws Exception {
    super.close();
    tableLoader.close();
    if (workerPool != null) {
      workerPool.shutdown();
    }
  }

  public static class SplitInfo {
    private final int version;
    private final byte[] split;

View on GitHub (pinned to 86d9c8fc54)