apache/iceberg · error · ValidationException

Illegal file type: %s

Error message

Illegal file type: %s

What it means

BaseSparkAction's file-counting collector validates the content type string of each deleted/added file group. If the type is neither DATA, POSITION_DELETES, EQUALITY_DELETES, nor a recognized metadata/manifest/statistics type, it throws ValidationException 'Illegal file type: %s', signaling unrecognized content in a file group.

Source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/actions/BaseSparkAction.java:331

        positionDeleteFilesCount.addAndGet(numFiles);

      } else if (FileContent.EQUALITY_DELETES.name().equalsIgnoreCase(type)) {
        equalityDeleteFilesCount.addAndGet(numFiles);

      } else if (MANIFEST.equalsIgnoreCase(type)) {
        manifestsCount.addAndGet(numFiles);

      } else if (MANIFEST_LIST.equalsIgnoreCase(type)) {
        manifestListsCount.addAndGet(numFiles);

      } else if (STATISTICS_FILES.equalsIgnoreCase(type)) {
        statisticsFilesCount.addAndGet(numFiles);

      } else if (OTHERS.equalsIgnoreCase(type)) {
        otherFilesCount.addAndGet(numFiles);

      } else {
        throw new ValidationException("Illegal file type: %s", type);
      }
    }

    public void deletedFile(String path, String type) {
      if (FileContent.DATA.name().equalsIgnoreCase(type)) {
        dataFilesCount.incrementAndGet();
        LOG.trace("Deleted data file: {}", path);

      } else if (FileContent.POSITION_DELETES.name().equalsIgnoreCase(type)) {
        positionDeleteFilesCount.incrementAndGet();
        LOG.trace("Deleted positional delete file: {}", path);

      } else if (FileContent.EQUALITY_DELETES.name().equalsIgnoreCase(type)) {
        equalityDeleteFilesCount.incrementAndGet();
        LOG.trace("Deleted equality delete file: {}", path);

      } else if (MANIFEST.equalsIgnoreCase(type)) {
        manifestsCount.incrementAndGet();

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Upgrade iceberg-spark to at least the version that wrote the table
  2. Inspect the file type string in the message and map it to the newest Iceberg spec
  3. Do not hand-edit table metadata; restore from a valid metadata snapshot if corrupted

Example fix

// before
} else {
  throw new ValidationException("Illegal file type: %s", type);
}
// after
} else if (POSITION_DELETES.equalsIgnoreCase(type)) {
  positionDeletesCount.addAndGet(numFiles);
} else {
  throw new ValidationException("Illegal file type: %s", type);
}
Defensive patterns

Strategy: validation

Validate before calling

Set<String> known = Set.of("DATA","POSITION_DELETES","EQUALITY_DELETES","MANIFEST","MANIFEST_LIST","INDEX","STATISTICS","OTHERS");
// before running actions, check no unknown content kinds appear in table files

Try / catch

try { action.execute(); } catch (ValidationException e) { if (e.getMessage().startsWith("Illegal file type")) { LOG.error("Table written by newer Iceberg? Upgrade the runtime.", e); throw e; } throw e; }

Prevention

When it happens

Trigger: Running Spark actions (e.g. expireSnapshots, removeOrphanFiles, deleteFileGroup path) against table metadata containing a ContentFile/manifest content type string this Iceberg version does not know — usually tables written by a newer Iceberg version.

Common situations: Version skew: a newer Iceberg writes a new file content kind, then an older iceberg-spark processes the table; corrupted or hand-edited metadata.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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