{"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/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/core.py#L7890-L7926","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nclient.xread({\"s\": \"0\"}, block=5000.0)\n// after\nclient.xread({\"s\": \"0\"}, block=5000)","handlingStrategy":"validation","validationCode":"def normalize_block(v):\n    if v is None:\n        return None\n    if not isinstance(v, int) or isinstance(v, bool):\n        raise TypeError(f\"block must be int (ms), got {type(v)}\")\n    if v < 0:\n        raise ValueError(f\"block must be >= 0, got {v}\")\n    return v\n\nblock = normalize_block(block_ms)\nclient.xread({\"s\": \"0\"}, block=block)","typeGuard":"def is_non_negative_int(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v >= 0","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    client.xread({\"s\": \"0\"}, block=block)\nexcept DataError as e:\n    if \"XREAD block\" in str(e):\n        client.xread({\"s\": \"0\"}, block=int(block))\n    else:\n        raise","preventionTips":["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)."],"tags":["redis-streams","validation","xread","dataerror"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}