{"record":{"id":"b213d31a60f50b16","repo":"vllm-project/vllm","slug":"only-readers-can-dequeue","errorCode":null,"errorMessage":"Only readers can dequeue","messagePattern":"Only readers can dequeue","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"vllm/distributed/device_communicators/shm_broadcast.py","lineNumber":906,"sourceCode":"        if self._is_local_reader:\n            with self.acquire_read(timeout, indefinite) as buf:\n                overflow = buf[0] == 1\n                if not overflow:\n                    offset = 3\n                    buf_count = from_bytes_big(buf[1:offset])\n                    all_buffers = []\n                    for i in range(buf_count):\n                        buf_offset = offset + 4\n                        buf_len = from_bytes_big(buf[offset:buf_offset])\n                        offset = buf_offset + buf_len\n                        all_buffers.append(buf[buf_offset:offset])\n                    obj = pickle.loads(all_buffers[0], buffers=all_buffers[1:])\n            if overflow:\n                obj = MessageQueue.recv(self.local_socket, timeout)\n        elif self._is_remote_reader:\n            obj = MessageQueue.recv(self.remote_socket, timeout)\n        else:\n            raise RuntimeError(\"Only readers can dequeue\")\n        return obj\n\n    @staticmethod\n    def recv(socket: zmq.Socket, timeout: float | None) -> Any:\n        # Ensure non-negative timeout passed to zmq poll.\n        timeout_ms = None if timeout is None else max(0, int(timeout * 1000))\n        if not socket.poll(timeout=timeout_ms):\n            raise TimeoutError\n        recv, *recv_oob = socket.recv_multipart(copy=False)\n        return pickle.loads(recv, buffers=recv_oob)\n\n    def broadcast_object(self, obj=None):\n        if self._is_writer:\n            self.enqueue(obj)\n            return obj\n        return self.dequeue()\n\n    @staticmethod","sourceCodeStart":888,"sourceCodeEnd":924,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/vllm/distributed/device_communicators/shm_broadcast.py#L888-L924","documentation":"MessageQueue.dequeue() only pulls objects from the shared-memory/ZMQ broadcast channel on processes registered as readers. The queue instance checks _is_local_reader and _is_remote_reader; when both are false the process is the writer (or was never registered as a reader), so there is nothing to dequeue and vLLM raises RuntimeError instead of blocking or returning garbage.","triggerScenarios":"Calling msg_queue.dequeue(timeout=...) on the process that created the MessageQueue in writer mode, or constructing a queue with reader_rank=None/local_reader_ranks=[] and then calling dequeue(). Also happens if a helper process re-imports and rebuilds the broadcast object instead of receiving the reader end.","commonSituations":"Custom multiprocessing code around vLLM's shm_broadcast (e.g. collecting logs/outputs from workers) where the developer calls dequeue() on the broadcaster; version changes that altered reader registration arguments in MessageQueue.__init__.","solutions":["Verify which process owns the object: only the ranks passed as readers at construction may call dequeue(); the creator/writer must call broadcast_object() instead","If you need to consume on this process, construct MessageQueue with this rank included in local_reader_ranks (or connect via remote_reader)","If you meant to send, call broadcast_object(obj) rather than dequeue()"],"exampleFix":"# before\nmq = MessageQueue(..., local_reader_ranks=[])\nobj = mq.dequeue()  # RuntimeError: Only readers can dequeue\n\n# after (writer side)\nmq = MessageQueue(..., local_reader_ranks=[1, 2])\nmq.broadcast_object(obj)  # this process writes, ranks 1-2 dequeue()","handlingStrategy":"validation","validationCode":"# before dequeue, assert this instance is a reader\nassert mq._is_local_reader or mq._is_remote_reader, (\n    \"dequeue() is reader-only; this process is the writer\"\n)","typeGuard":"def can_dequeue(mq: \"MessageQueue\") -> bool:\n    return bool(getattr(mq, \"_is_local_reader\", False) or getattr(mq, \"_is_remote_reader\", False))","tryCatchPattern":null,"preventionTips":["Register consumer ranks as local_reader_ranks/remote readers at MessageQueue construction","Only the broadcaster calls broadcast_object(); only reader ranks call dequeue()","Assert the reader flags before entering a dequeue loop in multi-process scaffolding"],"tags":["distributed","shared-memory","api-misuse"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}