apache/beam · error · IllegalArgumentException

Unknown endKeyCase:

Error message

Unknown endKeyCase: 

What it means

When converting a RowRange's end key into an internal EndPoint, BigtableServiceImpl switches over the protobuf endKeyCase. If the case is none of END_KEY_CLOSED, END_KEY_OPEN, an IllegalArgumentException with 'Unknown endKeyCase: ' is thrown.

Solutions

  1. Set either setEndKeyClosed or setEndKeyOpen on the RowRange before use
  2. Use RowRange.newBuilder().setEndKeyOpen(ByteString.EMPTY) to scan through the end of the table
  3. Validate ranges in the code that constructs them before handing them to the Beam source

Example fix

// before
RowRange range = RowRange.newBuilder().setStartKeyClosed(start).build(); // no end key
// after
RowRange range = RowRange.newBuilder()
    .setStartKeyClosed(start)
    .setEndKeyOpen(ByteString.EMPTY)
    .build();
Defensive patterns

Strategy: validation

Validate before calling

boolean hasEndKey(RowRange r) {
  return r.getEndKeyCase() != RowRange.EndKeyCase.ENDKEY_NOT_SET;
}

Type guard

boolean endKeySet(RowRange range) {
  return range.getEndKeyCase() == RowRange.EndKeyCase.END_KEY_CLOSED
      || range.getEndKeyCase() == RowRange.EndKeyCase.END_KEY_OPEN;
}

Prevention

When it happens

Trigger: Passing a RowRange whose end key is unset (neither setEndKeyClosed nor setEndKeyOpen called) to BigtableIO.withKeyRange, or a range whose proto oneof is in an unrecognized state.

Common situations: Building ranges dynamically where the end key computation failed silently and left the field unset; hand-crafted protos copied from different table configs.

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


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

Appendix: source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigtable/BigtableServiceImpl.java:789

    private final ByteString value;
    private final boolean isClosed;

    @NonNull
    static EndPoint extract(@NonNull RowRange rowRange) {
      switch (rowRange.getEndKeyCase()) {
        case ENDKEY_NOT_SET:
          return new EndPoint(ByteString.EMPTY, true);
        case END_KEY_CLOSED:
          return new EndPoint(rowRange.getEndKeyClosed(), true);
        case END_KEY_OPEN:
          if (rowRange.getEndKeyOpen().isEmpty()) {
            // Take care to normalize an open empty end key to be closed.
            return new EndPoint(ByteString.EMPTY, true);
          } else {
            return new EndPoint(rowRange.getEndKeyOpen(), false);
          }
        default:
          throw new IllegalArgumentException("Unknown endKeyCase: " + rowRange.getEndKeyCase());
      }
    }

    private EndPoint(@NonNull ByteString value, boolean isClosed) {
      this.value = value;
      this.isClosed = isClosed;
    }

    @Override
    public int compareTo(@NonNull EndPoint o) {
      return ComparisonChain.start()
          // Empty string comes last
          .compareFalseFirst(value.isEmpty(), o.value.isEmpty())
          .compare(value, o.value, ByteStringComparator.INSTANCE)
          // Open end point comes before a closed end point: [x,y) ends before [x,y].
          .compareFalseFirst(isClosed, o.isClosed)
          .result();
    }

View on GitHub (pinned to 12126d8942)