apache/beam · error · IllegalArgumentException
invalid redis cursor %s
Error message
invalid redis cursor %s
What it means
RedisCursor.redisCursorToByteKey converts a Redis SCAN cursor into a ByteKey by bit-reversing the cursor and encoding it with a coder. If coder.encode throws an IOException, it is converted to IllegalArgumentException('invalid redis cursor').
Source
Thrown at sdks/java/io/redis/src/main/java/org/apache/beam/sdk/io/redis/RedisCursor.java:126
https://engineering.q42.nl/redis-scan-cursor/
*/
@VisibleForTesting
static ByteKey redisCursorToByteKey(RedisCursor cursor) {
if ("0".equals(cursor.getCursor())) {
if (cursor.isStart()) {
return ByteKey.of(0x00);
} else {
return ByteKey.EMPTY;
}
}
int nBits = getTablePow(cursor.getDbSize());
long cursorLong = Long.parseLong(cursor.getCursor());
long reversed = shiftBits(cursorLong, nBits);
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
coder.encode(reversed, os);
} catch (IOException e) {
throw new IllegalArgumentException("invalid redis cursor " + cursor);
}
byte[] byteArray = os.toByteArray();
return ByteKey.copyFrom(byteArray);
}
@VisibleForTesting
static long shiftBits(long a, int nBits) {
long b = 0;
for (int i = 0; i < nBits; ++i) {
b <<= 1;
b |= (a & 1);
a >>= 1;
}
return b;
}
@VisibleForTesting
static int getTablePow(long nKeys) {View on GitHub (pinned to 12126d8942)
Solutions
- Ensure the cursor originates from an actual Redis SCAN response, not a hand-built value.
- Check that the cursor string is a valid non-negative decimal long within unsigned 64-bit range.
- Validate cursor round-tripping (byteKeyToRedisCursor) for custom cursor sources.
- Catch IllegalArgumentException and fall back to restarting the scan from cursor '0'.
Example fix
// before
RedisCursor cursor = RedisCursor.of("not-a-cursor"); // or non-SCAN source
// after
RedisCursor cursor = RedisCursor.of("17"); // taken directly from a SCAN reply Defensive patterns
Strategy: validation
Validate before calling
// Validate cursor before conversion
String c = cursor.getCursor();
if (c == null || !c.matches("\\d+")) { throw new IllegalArgumentException("cursor not from SCAN: " + c); }
Long.parseLong(c); // also check unsigned 64-bit range Type guard
boolean isValidRedisCursor(RedisCursor cursor) { try { long v = Long.parseLong(cursor.getCursor()); return v >= 0; } catch (NumberFormatException e) { return false; } } Try / catch
try { ByteKey k = RedisCursor.redisCursorToByteKey(cursor); } catch (IllegalArgumentException e) { cursor = RedisCursor.of("0"); /* restart scan */ } Prevention
- Only construct RedisCursor values from actual Redis SCAN replies.
- Round-trip test with RedisCursor.byteKeyToRedisCursor when persisting cursors.
- Clamp stored cursors to '0' on decode failure and rescan.
When it happens
Trigger: Converting a RedisCursor whose cursor string could be parsed but whose encoded long fails coder encoding (coder IO failure during ByteKeyRangeTracker setup).
Common situations: Programmatically constructed RedisCursor values not matching Redis's real cursor format; corrupted/edited cursor strings; Beam split bookkeeping handed a bogus cursor.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Failed to connect to host: %s, error: %s
- Cannot get a type descriptor for %s.
- Failed to import redis. You can ensure it is installed by in
- Cannot encode payload for WriteToPubSub. Expected valid stri
- error encoding bool: %v
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/5d9c4fef4fb85b95.
Report an issue: GitHub.