apache/iceberg · error · IllegalArgumentException
Unsupported isolation level: ${isolationLevel}
Error message
Unsupported isolation level: ${isolationLevel} What it means
SparkWrite.commit() dispatches to a commit strategy based on the configured IsolationLevel. Only SERIAL and SNAPSHOT isolation levels are recognized for branch writes; any other value throws IllegalArgumentException, indicating a corrupted or unknown isolation-level configuration.
Source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SparkWrite.java:460
int numAddedFiles = 0;
for (DataFile file : files(messages)) {
numAddedFiles += 1;
overwriteFiles.addFile(file);
}
// the scan may be null if the optimizer replaces it with an empty relation (e.g. false cond)
// no validation is needed in this case as the command does not depend on the table state
if (scan != null) {
switch (isolationLevel) {
case SERIALIZABLE:
commitWithSerializableIsolation(overwriteFiles, numOverwrittenFiles, numAddedFiles);
break;
case SNAPSHOT:
commitWithSnapshotIsolation(overwriteFiles, numOverwrittenFiles, numAddedFiles);
break;
default:
throw new IllegalArgumentException("Unsupported isolation level: " + isolationLevel);
}
} else {
commitOperation(
overwriteFiles,
String.format(
Locale.ROOT, "overwrite with %d new data files (no validation)", numAddedFiles));
}
}
private void commitWithSerializableIsolation(
OverwriteFiles overwriteFiles, int numOverwrittenFiles, int numAddedFiles) {
Long scanSnapshotId = scan.snapshotId();
if (scanSnapshotId != null) {
overwriteFiles.validateFromSnapshot(scanSnapshotId);
}
Expression conflictDetectionFilter = conflictDetectionFilter();View on GitHub (pinned to 86d9c8fc54)
Solutions
- Set write.*.isolation-level table properties only to 'serializable' or 'snapshot'.
- Fix typos in the isolation-level property so IsolationLevel.fromName resolves to a known value.
- Align Iceberg versions so the write path knows every IsolationLevel value.
Example fix
// before
ALTER TABLE t SET TBLPROPERTIES ('write.merge.isolation-level' = 'serial');
// after
ALTER TABLE t SET TBLPROPERTIES ('write.merge.isolation-level' = 'serializable'); Defensive patterns
Strategy: validation
Validate before calling
String level = table.properties().getOrDefault("write.merge.isolation-level", "serializable");
if (!level.equals("serializable") && !level.equals("snapshot")) {
throw new IllegalArgumentException("Invalid isolation level: " + level);
} Try / catch
try {
write.commit();
} catch (IllegalArgumentException e) {
logger.error("Bad write.*.isolation-level property", e);
} Prevention
- Only set isolation-level values to 'serializable' or 'snapshot'.
- Validate table properties after imports/migrations.
- Keep write path and enum versions in sync.
When it happens
Trigger: Committing a write whose isolationLevel resolved (from write.*.isolation-level table properties via IsolationLevel.fromName) to something other than SERIAL or SNAPSHOT — typically an unrecognized string mapping to an unexpected enum/null value.
Common situations: A typo'd isolation-level property value, a new IsolationLevel added in a newer version used with an older write path, or programmatic construction with a bogus value.
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
- Unsupported isolation level: + isolationLevel
- Unsupported operation mode: ${mode}
- Unsupported command: ${command}
- Unsupported isolation level: " + isolationLevel
- Unsupported isolation level:
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d7dad9dc1482f907.
Report an issue: GitHub.