{"record":{"id":"bdb19442c7cced7d","repo":"databendlabs/databend","slug":"memory-pool-is-closed","errorCode":null,"errorMessage":"memory pool is closed","messagePattern":"memory pool is closed","errorType":"exception","errorClass":"BrokenPipe","httpStatus":null,"severity":"error","filePath":"src/query/service/src/spillers/async_buffer.rs","lineNumber":128,"sourceCode":"        })\n    }\n\n    fn alloc_buffer(&self) -> io::Result<BytesMut> {\n        if let Ok(buf) = self.available_buffers.try_recv() {\n            return Ok(buf);\n        }\n\n        let allocated = self.allocated_chunks.fetch_add(1, Ordering::AcqRel);\n        if allocated < self.max_chunks {\n            return Ok(BytesMut::with_capacity(CHUNK_SIZE));\n        }\n\n        self.allocated_chunks.fetch_sub(1, Ordering::AcqRel);\n\n        let start = Instant::now();\n        let result = match self.available_buffers.recv_blocking() {\n            Ok(buf) => Ok(buf),\n            Err(_) => Err(io::Error::new(\n                io::ErrorKind::BrokenPipe,\n                \"memory pool is closed\",\n            )),\n        };\n        self.blocking_nanos\n            .fetch_add(start.elapsed().as_nanos() as u64, Ordering::Relaxed);\n        self.blocking_count.fetch_add(1, Ordering::Relaxed);\n        result\n    }\n\n    fn release_buffer(&self, buffer: BytesMut) {\n        if self.available_buffers_tx.try_send(buffer).is_err() {\n            unreachable!(\"MemoryPool available_buffers need unbounded.\");\n        }\n    }\n}\n\nimpl Drop for MemoryPool {","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/service/src/spillers/async_buffer.rs#L110-L146","documentation":"A sentinel error raised in AsyncBuffer::alloc_buffer when recv_blocking on the available_buffers channel fails, meaning the memory pool has been shut down while a caller was waiting for a buffer to become available. It fires during spill buffering after close/drop of the pool, signaling that no further allocations can be served.","triggerScenarios":"Thrown at src/query/service/src/spillers/async_buffer.rs:128 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the pool's shutdown/close state before attempting to allocate, and stop spilling work when the SpillLimiter or owning pool has been closed","Propagate the closure as a termination signal: cancel in-flight spill tasks and drain any pending alloc_buffer waiters instead of letting them error","Acquire the buffer before beginning a spill operation so closure is detected up front and partial writes are avoided","Wrap allocation in retry logic that first verifies pool liveness, returning a clean cancellation error rather than an io::Error on close"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}