apache/beam · error · IllegalArgumentException

Cannot set both endVersion and endTimestamp.

Error message

Cannot set both endVersion and endTimestamp.

What it means

expand() also enforces mutual exclusivity on the end bound: endVersion and endTimestamp cannot both be set. Each defines the end snapshot differently and combining them is ambiguous, so it throws IllegalArgumentException before reading.

Solutions

  1. Remove .withEndTimestamp(...) and keep .withEndVersion(v)
  2. Or remove .withEndVersion(...) and keep .withEndTimestamp(t)
  3. Sanitize pipeline options so only one end-bound field is ever populated

Example fix

// before
DeltaIO.read().withTable(path).withStartVersion(0L).withEndVersion(10L).withEndTimestamp("2024-06-01");
// after
DeltaIO.read().withTable(path).withStartVersion(0L).withEndVersion(10L);
Defensive patterns

Strategy: validation

Validate before calling

if (endVersion != null && endTimestamp != null) {
  throw new IllegalArgumentException("Choose either endVersion or endTimestamp, not both");
}

Prevention

When it happens

Trigger: Calling both .withEndVersion(v) and .withEndTimestamp(t) on the DeltaIO.read() builder.

Common situations: Same merged-config or copy-paste mistakes as the start-bound error; a generic read-range UI exposing both fields; accidental chaining while experimenting with bounded vs unbounded reads.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/056acc1cf5091208. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/io/delta/src/main/java/org/apache/beam/sdk/io/delta/DeltaIO.java:334

      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);

      TableImpl tableImpl = (TableImpl) table;

      long resolvedEndVersion;
      Long endVersionVal = getEndVersion();
      String endTimestampVal = getEndTimestamp();
      if (endVersionVal != null) {

View on GitHub (pinned to 12126d8942)