redis/redis-py · error · DataError
XREAD block must be a non-negative integer
Error message
XREAD block must be a non-negative integer
What it means
Raised by xread() when the block argument is not an int or is negative. block is the millisecond timeout for the blocking XREAD; 0 means block indefinitely, so the allowed range is int >= 0. Strict isinstance(block, int) rejects strings and floats.
Source
Thrown at redis/commands/core.py:7908
max_count: if set, cap the total number of entries returned across all
streams combined. Unlike ``count`` (a per-stream limit),
this is a cumulative cap over the whole reply. Must be a
positive integer and, when ``count`` is also set, must be
greater than or equal to ``count``. Requires Redis >= 8.10.0.
max_size: if set, a soft cap on the total server reply size in bytes
across all streams combined. Measured server-side including
protocol overhead, so it is not an exact application-payload
size guarantee; a single available entry larger than the cap
may still be returned. Must be a positive integer. Requires
Redis >= 8.10.0.
For more information, see https://redis.io/commands/xread
"""
pieces = []
if block is not None:
if not isinstance(block, int) or block < 0:
raise DataError("XREAD block must be a non-negative integer")
pieces.append(b"BLOCK")
pieces.append(str(block))
if count is not None:
if not isinstance(count, int) or count < 1:
raise DataError("XREAD count must be a positive integer")
pieces.append(b"COUNT")
pieces.append(str(count))
if max_count is not None:
if not isinstance(max_count, int) or max_count < 1:
raise DataError("XREAD max_count must be a positive integer")
if count is not None and max_count < count:
raise DataError(
"XREAD max_count must be greater than or equal to count"
)
pieces.append(b"MAXCOUNT")
pieces.append(str(max_count))
if max_size is not None:
if not isinstance(max_size, int) or max_size < 1:View on GitHub (pinned to da03cdc7e8)
Solutions
- Pass an int >= 0 representing milliseconds (e.g. block=5000 for 5s).
- Use block=0 for indefinite blocking, or omit/None for non-blocking.
- Coerce: block = int(block_ms) if block_ms is not None else None.
Example fix
// before
client.xread({"s": "0"}, block=5000.0)
// after
client.xread({"s": "0"}, block=5000) Defensive patterns
Strategy: validation
Validate before calling
def normalize_block(v):
if v is None:
return None
if not isinstance(v, int) or isinstance(v, bool):
raise TypeError(f"block must be int (ms), got {type(v)}")
if v < 0:
raise ValueError(f"block must be >= 0, got {v}")
return v
block = normalize_block(block_ms)
client.xread({"s": "0"}, block=block) Type guard
def is_non_negative_int(v) -> bool:
return isinstance(v, int) and not isinstance(v, bool) and v >= 0 Try / catch
from redis.exceptions import DataError
try:
client.xread({"s": "0"}, block=block)
except DataError as e:
if "XREAD block" in str(e):
client.xread({"s": "0"}, block=int(block))
else:
raise Prevention
- Document block in milliseconds everywhere it surfaces to users.
- Use 0 for indefinite blocking, None for non-blocking — don't conflate.
- Coerce block from seconds: block_ms = int(seconds * 1000).
When it happens
Trigger: Call client.xread(streams, block=...) with block as a float, string, negative number, or non-int type. block=0 is valid (block forever); block=None (default) means non-blocking.
Common situations: Passing seconds instead of milliseconds (e.g. block=5 meaning 5s, but XREAD treats it as 5ms — not an error but a semantic bug); config loading block as a string; arithmetic producing floats.
Related errors
- XREAD count must be a positive integer
- XREAD max_count must be a positive integer
- XRANGE count must be a positive integer
- CLIENT KILL type must be one of {client_types!r}
- CLIENT KILL skipme must be a bool
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/ef471467a7ec22cd.json.
Report an issue: GitHub.