apache/iceberg · error · UncheckedIOException

Failed to delete file:

Error message

Failed to delete file: 

What it means

dropTable() deletes the table directory after dropping data; if the filesystem delete raises IOException it is wrapped in UncheckedIOException with this message. The table metadata may have been logically dropped while physical cleanup failed, so this can leave partial state.

Solutions

  1. Check the wrapped IOException cause and fix FS availability/permissions, then retry dropTable
  2. Manually delete leftover table directory (hdfs dfs -rm -r) once the FS is healthy
  3. Verify the calling user has write/delete permission on the table path
  4. Retry with valid credentials if Kerberos/Token expired

Example fix

// before: unchecked failure
tables.dropTable(location);
// after
try {
  tables.dropTable(location);
} catch (UncheckedIOException e) {
  LOG.warn("cleanup failed, retry later", e); // table dir may remain
}
Defensive patterns

Strategy: try-catch

Validate before calling

Path p = new Path(location);
FileSystem fs = Util.getFs(p, conf);
if (!fs.exists(p)) return true; // nothing to drop
fs.access(p, FsAction.WRITE); // throws if no delete permission

Try / catch

try { tables.dropTable(location); } catch (UncheckedIOException e) { LOG.error("FS delete failed: {}", e.getCause().toString()); /* retry or manual cleanup */ }

Prevention

When it happens

Trigger: Util.getFs(...).delete(tablePath, true) throwing due to HDFS unavailability, permission denied on the directory, or network failure during dropTable().

Common situations: HDFS NameNode down or in safe mode during a drop; insufficient permissions to delete the table directory; dropping tables in a loop when one FS becomes unreachable; Kerberos token expiry mid-operation.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/hadoop/HadoopTables.java:200

    if (ops.current() != null) {
      if (purge) {
        lastMetadata = ops.current();
      }
    } else {
      return false;
    }

    try {
      if (purge && lastMetadata != null) {
        // Since the data files and the metadata files may store in different locations,
        // so it has to call dropTableData to force delete the data file.
        CatalogUtil.dropTableData(ops.io(), lastMetadata);
      }
      Path tablePath = new Path(location);
      Util.getFs(tablePath, conf).delete(tablePath, true /* recursive */);
      return true;
    } catch (IOException e) {
      throw new UncheckedIOException("Failed to delete file: " + location, e);
    }
  }

  @VisibleForTesting
  TableOperations newTableOps(String location) {
    if (location.contains(METADATA_JSON)) {
      return new StaticTableOperations(location, new HadoopFileIO(conf));
    } else {
      return new HadoopTableOperations(
          new Path(location), new HadoopFileIO(conf), conf, createOrGetLockManager(this));
    }
  }

  private static synchronized LockManager createOrGetLockManager(HadoopTables table) {
    if (lockManager == null) {
      Map<String, String> properties = table.conf.getPropsWithPrefix(LOCK_PROPERTY_PREFIX);
      lockManager = LockManagers.from(properties);
    }

View on GitHub (pinned to 86d9c8fc54)