apache/beam · error · IllegalArgumentException

Unknown startKeyCase:

Error message

Unknown startKeyCase: 

What it means

When converting a RowRange's start key into an internal StartPoint, BigtableServiceImpl switches over the protobuf startKeyCase. If the case is none of START_KEY_CLOSED, START_KEY_OPEN (i.e. the range is in an unexpected/uninitialized state), an IllegalArgumentException with 'Unknown startKeyCase: ' is thrown.

Solutions

  1. Always set one of startKeyClosed or startKeyOpen on the RowRange before passing it to BigtableIO.withKeyRange
  2. Use RowRange.newBuilder().setStartKeyClosed(ByteString.EMPTY) to scan from the beginning of the table
  3. Log/print rowRange.getStartKeyCase() to verify which case your range actually has

Example fix

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

Strategy: validation

Validate before calling

boolean hasStartKey(RowRange r) {
  return r.getStartKeyCase() != RowRange.StartKeyCase.STARTKEY_NOT_SET;
}

Type guard

boolean startKeySet(RowRange range) {
  return range.getStartKeyCase() == RowRange.StartKeyCase.START_KEY_CLOSED
      || range.getStartKeyCase() == RowRange.StartKeyCase.START_KEY_OPEN;
}

Prevention

When it happens

Trigger: Passing a RowRange to BigtableIO.withKeyRange whose start key is unset — e.g. a default-constructed RowRange without setStartKeyClosed/setStartKeyOpen, or a range built from a different proto version where the oneof field isn't populated.

Common situations: Programmatically building RowRanges and forgetting to set a start key; deserializing ranges from external config where the start key field was dropped.

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/6864de2dbe501505. 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:748

    private final ByteString value;
    private final boolean isClosed;

    @NonNull
    static StartPoint extract(@NonNull RowRange rowRange) {
      switch (rowRange.getStartKeyCase()) {
        case STARTKEY_NOT_SET:
          return new StartPoint(ByteString.EMPTY, true);
        case START_KEY_CLOSED:
          return new StartPoint(rowRange.getStartKeyClosed(), true);
        case START_KEY_OPEN:
          if (rowRange.getStartKeyOpen().isEmpty()) {
            // Take care to normalize an open empty start key to be closed.
            return new StartPoint(ByteString.EMPTY, true);
          } else {
            return new StartPoint(rowRange.getStartKeyOpen(), false);
          }
        default:
          throw new IllegalArgumentException("Unknown startKeyCase: " + rowRange.getStartKeyCase());
      }
    }

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

    @Override
    public int compareTo(@NonNull StartPoint o) {
      return ComparisonChain.start()
          // Empty string comes first
          .compareTrueFirst(value.isEmpty(), o.value.isEmpty())
          .compare(value, o.value, ByteStringComparator.INSTANCE)
          // Closed start point comes before an open start point: [x,y] starts before (x,y].
          .compareTrueFirst(isClosed, o.isClosed)
          .result();
    }

View on GitHub (pinned to 12126d8942)