apache/iceberg · error · IllegalArgumentException
Unexpected command:
Error message
Unexpected command:
What it means
SparkWriteConf.copyOnWriteDistributionMode resolves the distribution mode for a copy-on-write write based on the RowLevelCommand (DELETE, UPDATE, MERGE). If the command is none of these, it throws IllegalArgumentException("Unexpected command: " + command), signaling a programming error rather than user misconfiguration - the command enum was extended or an unexpected value was passed.
Source
Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/SparkWriteConf.java:369
return SparkWriteUtil.copyOnWriteRequirements(
table,
command,
copyOnWriteDistributionMode(command),
fanoutWriterEnabled(),
dataAdvisoryPartitionSize());
}
@VisibleForTesting
DistributionMode copyOnWriteDistributionMode(Command command) {
switch (command) {
case DELETE:
return deleteDistributionMode();
case UPDATE:
return updateDistributionMode();
case MERGE:
return copyOnWriteMergeDistributionMode();
default:
throw new IllegalArgumentException("Unexpected command: " + command);
}
}
public SparkWriteRequirements positionDeltaRequirements(Command command) {
if (ignoreTableDistributionAndOrdering()) {
LOG.info("Skipping distribution/ordering: disabled per job configuration");
return SparkWriteRequirements.EMPTY;
}
return SparkWriteUtil.positionDeltaRequirements(
table,
command,
positionDeltaDistributionMode(command),
fanoutWriterEnabled(),
command == DELETE ? deleteAdvisoryPartitionSize() : dataAdvisoryPartitionSize());
}
@VisibleForTestingView on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure all Iceberg modules are the same version so Command enums and SparkWriteConf branches match
- Only call copyOnWriteDistributionMode for row-level commands (DELETE/UPDATE/MERGE); route other commands elsewhere
- If a new Command constant was introduced, update the switch to handle it
Example fix
// before
DistributionMode mode = writeConf.copyOnWriteDistributionMode(Command.INSERT); // throws
// after
if (command == Command.INSERT) {
mode = writeConf.distributionMode(); // append path
} else {
mode = writeConf.copyOnWriteDistributionMode(command);
} Defensive patterns
Strategy: validation
Validate before calling
if (command != Command.DELETE && command != Command.UPDATE && command != Command.MERGE) {
throw new IllegalArgumentException("CoW distribution mode requires DELETE/UPDATE/MERGE, got: " + command);
} Type guard
boolean isRowLevelCommand(Command c) {
return c == Command.DELETE || c == Command.UPDATE || c == Command.MERGE;
} Try / catch
try {
mode = writeConf.copyOnWriteDistributionMode(command);
} catch (IllegalArgumentException e) {
LOG.warn("Unexpected command {}, defaulting distribution mode", command, e);
mode = writeConf.distributionMode();
} Prevention
- Route append/CTAS writes to the general distributionMode API, not the CoW row-level one
- Keep all Iceberg modules on identical versions
- Add exhaustive switch handling when Command gains new constants
- Unit-test write conf resolution for each Command value
When it happens
Trigger: Passing a Command value other than DELETE, UPDATE, or MERGE (e.g. Command.INSERT or a newly added enum constant) into copyOnWriteDistributionMode via the write-conf resolution path.
Common situations: Upgrading Iceberg where a new RowLevelCommand constant was added but SparkWriteConf branches were not updated (version mismatch between modules); custom code invoking the conf method with an unexpected command.
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
- Unexpected distribution mode:
- Invalid distribution mode: %s
- Invalid file format: %s
- Cannot support given S3 encryption type:
- Unknown planning mode: ${mode}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/7f0f1ad64c6347bb.
Report an issue: GitHub.