{"record":{"id":"ef471467a7ec22cd","repo":"redis/redis-py","slug":"xread-block-must-be-a-non-negative-integer","errorCode":null,"errorMessage":"XREAD block must be a non-negative integer","messagePattern":"XREAD block must be a non-negative integer","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":7908,"sourceCode":"        max_count: if set, cap the total number of entries returned across all\n                   streams combined. Unlike ``count`` (a per-stream limit),\n                   this is a cumulative cap over the whole reply. Must be a\n                   positive integer and, when ``count`` is also set, must be\n                   greater than or equal to ``count``. Requires Redis >= 8.10.0.\n\n        max_size: if set, a soft cap on the total server reply size in bytes\n                  across all streams combined. Measured server-side including\n                  protocol overhead, so it is not an exact application-payload\n                  size guarantee; a single available entry larger than the cap\n                  may still be returned. Must be a positive integer. Requires\n                  Redis >= 8.10.0.\n\n        For more information, see https://redis.io/commands/xread\n        \"\"\"\n        pieces = []\n        if block is not None:\n            if not isinstance(block, int) or block < 0:\n                raise DataError(\"XREAD block must be a non-negative integer\")\n            pieces.append(b\"BLOCK\")\n            pieces.append(str(block))\n        if count is not None:\n            if not isinstance(count, int) or count < 1:\n                raise DataError(\"XREAD count must be a positive integer\")\n            pieces.append(b\"COUNT\")\n            pieces.append(str(count))\n        if max_count is not None:\n            if not isinstance(max_count, int) or max_count < 1:\n                raise DataError(\"XREAD max_count must be a positive integer\")\n            if count is not None and max_count < count:\n                raise DataError(\n                    \"XREAD max_count must be greater than or equal to count\"\n                )\n            pieces.append(b\"MAXCOUNT\")\n            pieces.append(str(max_count))\n        if max_size is not None:\n            if not isinstance(max_size, int) or max_size < 1:","sourceCodeStart":7890,"sourceCodeEnd":7926,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L7890-L7926","documentation":"Raised by xread() (redis/commands/core.py:7908) as a DataError when block is not an int or is negative. block is the BLOCK milliseconds argument to XREAD; 0 means block indefinitely, so the lower bound is inclusive (>= 0). Validation happens client-side before the command is built.","triggerScenarios":"Calling client.xread(streams, block=-1), block=1.5, block='5000', or block=True. block=0 is valid and means 'block forever'.","commonSituations":"Reading block timeout from env/config as a string, computing a negative timeout from a timestamp diff that went negative (clock skew), or treating block=0 as 'no block' (it actually means infinite block - use None for non-blocking).","solutions":["Pass a non-negative int (>= 0) for block, or None to make the call non-blocking.","Remember block=0 means block indefinitely; pass None when you want no blocking.","Clamp computed timeouts: block = max(0, int(deadline - now_ms))."],"exampleFix":"# before\nclient.xread({'mystream': '$'}, block=deadline_ms - now_ms)\n# after\nblock_ms = max(0, int(deadline_ms - now_ms))\nclient.xread({'mystream': '$'}, block=block_ms)","handlingStrategy":"validation","validationCode":"def safe_xread_block(block):\n    if block is None:\n        return None\n    if not isinstance(block, int) or isinstance(block, bool) or block < 0:\n        raise DataError('XREAD block must be a non-negative int')\n    return block","typeGuard":"def is_valid_xread_block(b) -> bool:\n    return isinstance(b, int) and not isinstance(b, bool) and b >= 0","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    client.xread(streams, block=timeout)\nexcept DataError as e:\n    if 'block' in str(e):\n        client.xread(streams)  # fall back to non-blocking\n    else:\n        raise","preventionTips":["Remember block=0 means block forever; use None for non-blocking.","Clamp computed timeouts to max(0, ...) to avoid negatives from clock skew.","Keep block as an int through your pipeline - do not stringify."],"tags":["streams","xread","argument-validation","dataerror"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}