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
- Always set one of startKeyClosed or startKeyOpen on the RowRange before passing it to BigtableIO.withKeyRange
- Use RowRange.newBuilder().setStartKeyClosed(ByteString.EMPTY) to scan from the beginning of the table
- 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
- Always call setStartKeyClosed/setStartKeyOpen when constructing ranges
- Treat an empty start key as setStartKeyClosed(ByteString.EMPTY), not omitted
- Unit-test range builders to assert the oneof case is set
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
- Unknown endKeyCase:
- bulk apply procces failed
- BulkMutation took too long to close
- could not apply mutation for row key=
- could not apply mutation
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)