apache/beam · error · IllegalArgumentException
Either startVersion or startTimestamp must be set.
Error message
Either startVersion or startTimestamp must be set.
What it means
expand() requires a starting point for the Delta read: either startVersion or startTimestamp must be provided. The connector does not yet default to the current/latest snapshot for unbounded reads (per the TODO), so a read with no start bound cannot be planned and throws IllegalArgumentException.
Source
Thrown at sdks/java/io/delta/src/main/java/org/apache/beam/sdk/io/delta/DeltaIO.java:328
}
}
return toBuilder().setMetadataColumns(Arrays.asList(metadataColumns)).build();
}
public ReadChanges withConfig(Map<String, String> config) {
return toBuilder().setHadoopConfig(config).build();
}
@Override
public PCollection<Row> expand(PBegin input) {
String path = getTablePath();
if (path == null) {
throw new IllegalArgumentException("Table path must be set.");
}
if (getStartVersion() == null && getStartTimestamp() == null) {
// TODO: for unbounded reads, support using current HEAD or the latest snapshot
// as the default starting point.
throw new IllegalArgumentException("Either startVersion or startTimestamp must be set.");
}
if (getStartVersion() != null && getStartTimestamp() != null) {
throw new IllegalArgumentException("Cannot set both startVersion and startTimestamp.");
}
if (getEndVersion() != null && getEndTimestamp() != null) {
throw new IllegalArgumentException("Cannot set both endVersion and endTimestamp.");
}
Configuration conf = new Configuration();
Map<String, String> hadoopConfig = getHadoopConfig();
if (hadoopConfig != null) {
for (Map.Entry<String, String> entry : hadoopConfig.entrySet()) {
conf.set(entry.getKey(), entry.getValue());
}
}
Engine engine = DefaultEngine.create(conf);
Table table = Table.forPath(engine, path);
View on GitHub (pinned to 12126d8942)
Solutions
- Call .withStartVersion(long) with the desired snapshot version (e.g. 0 for full history)
- Or call .withStartTimestamp(String/Instant) to start at a point in time
- If you want 'latest', resolve the current version out-of-band and pass it explicitly as startVersion
Example fix
// before DeltaIO.read().withTable(path).withEndVersion(10L); // after DeltaIO.read().withTable(path).withStartVersion(0L).withEndVersion(10L);
Defensive patterns
Strategy: validation
Validate before calling
if (startVersion == null && startTimestamp == null) {
throw new IllegalArgumentException("Set either .withStartVersion(...) or .withStartTimestamp(...)");
} Prevention
- Always set a start bound (version 0 for a full read is a safe default)
- Ensure option-parsing code never leaves both start fields null
- Document in pipeline options that a start point is mandatory for Delta reads
When it happens
Trigger: Building DeltaIO.read() with a table path but never calling .withStartVersion() or .withStartTimestamp() before applying the transform.
Common situations: Copy-pasting example code that sets endVersion/endTimestamp but omits the start bound; migrating from a default-HEAD style API; assuming a streaming/unbounded read starts at latest snapshot automatically.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Batch size is too large! It should be smaller or equal than
- Column delimiter should be set if headers are present.
- Column headers should be supplied when delimiter is present.
- Cannot set both startVersion and startTimestamp.
- Cannot set both endVersion and endTimestamp.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/1019979f95d6bd49.
Report an issue: GitHub.