{"record":{"id":"789da40637d055fd","repo":"python/cpython","slug":"readinto-returned-n-outside-buffer-size-len-b","errorCode":null,"errorMessage":"readinto returned {n} outside buffer size {len(b)}","messagePattern":"readinto returned (.+?) outside buffer size (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":625,"sourceCode":"    # primitive operation, but that would lead to nasty recursion in case\n    # a subclass doesn't implement either.)\n\n    def read(self, size=-1):\n        \"\"\"Read and return up to size bytes, where size is an int.\n\n        Returns an empty bytes object on EOF, or None if the object is\n        set not to block and has no data to read.\n        \"\"\"\n        if size is None:\n            size = -1\n        if size < 0:\n            return self.readall()\n        b = bytearray(size.__index__())\n        n = self.readinto(b)\n        if n is None:\n            return None\n        if n < 0 or n > len(b):\n            raise ValueError(f\"readinto returned {n} outside buffer size {len(b)}\")\n        del b[n:]\n        return b.take_bytes()\n\n    def readall(self):\n        \"\"\"Read until EOF, using multiple read() call.\"\"\"\n        res = bytearray()\n        while data := self.read(DEFAULT_BUFFER_SIZE):\n            res += data\n        if res:\n            return res.take_bytes()\n        else:\n            # b'' or None\n            return data\n\n    def readinto(self, b):\n        \"\"\"Read bytes into a pre-allocated bytes-like object b.\n\n        Returns an int representing the number of bytes read (0 for EOF), or","sourceCodeStart":607,"sourceCodeEnd":643,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L607-L643","documentation":"Raised by IOBase.read (Lib/_pyio.py:625) after it allocates a bytearray of `size` and delegates to readinto(b): the raw stream's readinto must return either None (non-blocking, no data) or an integer 0 <= n <= len(b). A return value outside that range violates the readinto contract, so the io layer raises ValueError rather than return corrupted data.","triggerScenarios":"A custom raw stream class whose readinto() returns the wrong variable (e.g. total bytes of the source instead of bytes copied into the buffer); readinto returning -1 for EOF; readinto writing into the buffer but returning a stale/hardcoded length; a subclass of io.RawIOBase that skips the base implementation.","commonSituations":"Implementing in-memory or socket-based RawIOBase subclasses for testing, mocking, or wrapping proprietary transports; porting C extension streams where the return convention differs; mocking readinto in tests with a MagicMock that returns a Mock, not an int.","solutions":["Audit the custom readinto(): it must copy at most len(buffer) bytes and return the exact number of bytes actually written.","Return 0 to signal EOF and None only for non-blocking streams with no data available.","In tests, configure mocks explicitly: `mock_stream.readinto.return_value = 0`.","Inherit from io.RawIOBase / io.IOBase and reuse their read() default, which routes through a correct readinto or vice versa."],"exampleFix":"# before\nclass MemRaw(io.RawIOBase):\n    def readinto(self, b):\n        data = self._src.read(len(b))\n        b[:len(data)] = data\n        return len(self._src)  # wrong: total length, not bytes copied\n\n# after\nclass MemRaw(io.RawIOBase):\n    def readinto(self, b):\n        data = self._src.read(len(b))\n        b[:len(data)] = data\n        return len(data)  # exact count of bytes written into b","handlingStrategy":"validation","validationCode":"n = raw.readinto(b)\nif n is not None and not (0 <= n <= len(b)):\n    raise ValueError(f'custom readinto misbehaved: {n}')  # fail fast with context","typeGuard":null,"tryCatchPattern":"try:\n    data = raw.read(4096)\nexcept ValueError as e:\n    if 'readinto returned' in str(e):\n        raise RuntimeError('bug in custom raw stream: readinto contract violated') from e\n    raise","preventionTips":["Inherit from io.RawIOBase and follow the return contract: 0 for EOF, exact bytes-copied otherwise.","Write a unit test asserting 0 <= readinto(buf) <= len(buf) across EOF and full-buffer cases.","Configure test mocks with concrete ints: mock.readinto.return_value = 0."],"tags":["io","readinto","custom-stream","invariant","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}