apache/beam · error · IllegalArgumentException

For a cycling sequence generator, both 'start' and 'end'…

Error message

For a cycling sequence generator, both 'start' and 'end' must be specified.

What it means

A sequence generator needs an explicit range to cycle over. If only one of 'fields.<name>.start' and 'fields.<name>.end' is provided (the other missing), the cycle bounds cannot be computed and an IllegalArgumentException is thrown. Note: if BOTH are missing, the generator falls back to using the row index.

Solutions

  1. Specify both 'fields.<name>.start' and 'fields.<name>.end' in the table properties.
  2. Remove both keys if you want the default index-based generator.
  3. If an ever-increasing counter is desired, omit both and use the returned index generator, or set a large 'end'.

Example fix

// before
'{"fields":{"id":{"kind":"sequence","start":1}}}'
// after
'{"fields":{"id":{"kind":"sequence","start":1,"end":100}}}'
Defensive patterns

Strategy: validation

Validate before calling

JsonNode start = props.path("fields." + name + ".start");
JsonNode end = props.path("fields." + name + ".end");
if (start.isMissingNode() != end.isMissingNode()) {
  throw new IllegalArgumentException(name + ": both start and end required");
}

Try / catch

try { buildRowFn(props); } catch (IllegalArgumentException e) { /* add missing bound or remove both */ }

Prevention

When it happens

Trigger: Setting fields.<name>.start without fields.<name>.end (or vice versa) with kind='sequence' on an integer datagen field.

Common situations: Partial copy-paste of TBLPROPERTIES JSON; someone removed the 'end' key assuming 'start' alone is an incrementing counter.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/datagen/DataGeneratorRowFn.java:132

    }

    if ("sequence".equalsIgnoreCase(kind)) {
      if (!SqlTypeName.INT_TYPES.contains(sqlTypeName)) {
        throw new IllegalArgumentException(
            String.format(
                "The 'sequence' generator for integers only supports integer types, but field '%s' is of type '%s'.",
                field.getName(), sqlTypeName));
      }

      JsonNode startNode = properties.path("fields." + fieldName + ".start");
      JsonNode endNode = properties.path("fields." + fieldName + ".end");

      if (startNode.isMissingNode() && endNode.isMissingNode()) {
        return (index) -> index;
      }

      if (startNode.isMissingNode() || endNode.isMissingNode()) {
        throw new IllegalArgumentException(
            "For a cycling sequence generator, both 'start' and 'end' must be specified.");
      }

      long start = startNode.asLong(0L);
      long end = endNode.asLong(Long.MAX_VALUE);

      if (start > end) {
        throw new IllegalArgumentException(
            String.format(
                "For sequence generator, 'start' (%d) cannot be greater than 'end' (%d).",
                start, end));
      }
      long cycleLength = end - start + 1;
      switch (sqlTypeName) {
        case INTEGER:
          return (index) -> (int) (start + (index % cycleLength));
        case SMALLINT:
          return (index) -> (short) (start + (index % cycleLength));

View on GitHub (pinned to 12126d8942)