apache/iceberg · error · IllegalArgumentException
Unexpected command: ${command}
Error message
Unexpected command: ${command} What it means
SparkWriteConf.copyOnWriteDistributionMode maps a Spark write Command (DELETE, UPDATE, MERGE, OVERWRITE/INSERT) to a distribution mode and throws IllegalArgumentException('Unexpected command: ' + command) for any Command outside the switch's cases. The write configuration only supports distribution-mode resolution for the recognized DML commands; anything else is a caller bug.
Source
Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkWriteConf.java:379
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
- Pass the correct Command enum constant (DELETE, UPDATE, or MERGE) for a copy-on-write distribution lookup
- For plain append/overwrite writes, use the appropriate SparkWriteConf methods (e.g. distributionMode()) rather than the CoW-specific one
- Upgrade Iceberg if a newly introduced Command constant is not handled
- Add a case for the new command if you maintain a fork of SparkWriteConf
Example fix
// before DistributionMode mode = writeConf.copyOnWriteDistributionMode(Command.INSERT); // throws // after DistributionMode mode = writeConf.distributionMode(); // correct entry point for appends
Defensive patterns
Strategy: validation
Validate before calling
if (command != Command.DELETE && command != Command.UPDATE && command != Command.MERGE) {
throw new IllegalArgumentException("copyOnWriteDistributionMode requires DELETE/UPDATE/MERGE, got " + command);
} Type guard
boolean isCoWCommand(Command c) { return c == Command.DELETE || c == Command.UPDATE || c == Command.MERGE; } Try / catch
try {
mode = writeConf.copyOnWriteDistributionMode(command);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Unexpected command")) { mode = writeConf.distributionMode(); }
else throw e;
} Prevention
- Call copyOnWriteDistributionMode only for row-level DML commands
- Use writeConf.distributionMode() for append/overwrite writes
- Update switches whenever the Command enum gains new constants
When it happens
Trigger: Querying copyOnWriteDistributionMode(command) with a Command other than DELETE/UPDATE/MERGE (e.g. a plain INSERT/OVERWRITE command instance passed in error, or an unexpected enum constant), typically from internal write-planning code.
Common situations: Library-internal misuse or version mismatch where a new Command constant was added but the switch wasn't updated; custom extensions calling SparkWriteConf directly with the wrong 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 command: command
- Unknown position for reorder: <update.position()>
- Class %s does not implement DynamicRecordGeneratorSQL
- Procedure ${ident} not found
- Unable to parse sortOrder: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/708f0b4cd9f9d0b5.
Report an issue: GitHub.