{"record":{"id":"24fb0fb2d697c43d","repo":"zellij-org/zellij","slug":"exceeded-log-buffer-size-make-sure-that-your-plug","errorCode":null,"errorMessage":"Exceeded log buffer size. Make sure that your plugin calls flush on stderr on valid UTF-8 symbol boundary. Additionally, make sure that your log message contains endline \\n symbol.","messagePattern":"Exceeded log buffer size\\. Make sure that your plugin calls flush on stderr on valid UTF-8 symbol boundary\\. Additionally, make sure that your log message contains endline \\\\n symbol\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"zellij-server/src/logging_pipe.rs","lineNumber":47,"sourceCode":"            \"|{:<25.25}| {} [{:<10.15}] {}\",\n            self.plugin_name,\n            chrono::Local::now().format(\"%Y-%m-%d %H:%M:%S.%3f\"),\n            format!(\"id: {}\", self.plugin_id),\n            message\n        );\n    }\n}\n\nimpl Write for LoggingPipe {\n    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {\n        if self.buffer.len() + buf.len() > ZELLIJ_MAX_PIPE_BUFFER_SIZE {\n            let error_msg =\n                \"Exceeded log buffer size. Make sure that your plugin calls flush on stderr on \\\n                valid UTF-8 symbol boundary. Additionally, make sure that your log message contains \\\n                endline \\\\n symbol.\";\n            error!(\"{}: {}\", self.plugin_name, error_msg);\n            self.buffer.clear();\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidData,\n                error_msg,\n            ));\n        }\n\n        self.buffer.extend(buf);\n        self.flush()?;\n\n        Ok(buf.len())\n    }\n\n    // When we flush, check if current buffer is valid utf8 string, split by '\\n' and truncate buffer in the process.\n    // We assume that eventually, flush will be called on valid string boundary (i.e. std::str::from_utf8(..).is_ok() returns true at some point).\n    // Above assumption might not be true, in which case we'll have to think about it. Make it simple for now.\n    fn flush(&mut self) -> std::io::Result<()> {\n        self.buffer.make_contiguous();\n\n        match std::str::from_utf8(self.buffer.as_slices().0) {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-server/src/logging_pipe.rs#L29-L65","documentation":"Returned by LoggingPipe::write when a plugin's pending stderr buffer would exceed ZELLIJ_MAX_PIPE_BUFFER_SIZE (16384 bytes). The pipe accumulates bytes and only drains on flush when the buffer forms complete, newline-terminated UTF-8 lines; without newlines the buffer grows until this hard cap trips, the buffer is discarded, and the plugin sees an InvalidData error on stderr.","triggerScenarios":"A WASM plugin that writes more than 16KiB to stderr without emitting a '\\n' (e.g. using print! in a loop, writing partial UTF-8 sequences, or never flushing), so flush() can never split and drain the buffer.","commonSituations":"Plugins ported from host programs that log giant single-line blobs; eprintln! with embedded '\\r' but no '\\n'; a plugin panicking and dumping a huge message without newline; plugins writing binary data to stderr.","solutions":["End every stderr log line with '\\n' (use eprintln! rather than eprint!)","Flush stderr after each log statement or logical batch","Chunk or truncate very large messages (e.g. log first 1KiB of a payload) so a single line stays well under 16KiB","Never write non-UTF-8 or partial multibyte sequences without flushing at character boundaries"],"exampleFix":"// before (Rust plugin)\neprint!(\"long diagnostic without newline: {}\", huge_string);\n\n// after\neprintln!(\"diagnostic: {}\", &huge_string[..huge_string.len().min(1024)]);","handlingStrategy":"validation","validationCode":"const MAX_PIPE_BUFFER: usize = 16_384;\nfn stderr_chunk_is_safe(chunk: &[u8], pending: usize) -> bool {\n    pending + chunk.len() <= MAX_PIPE_BUFFER\n        && chunk.ends_with(b\"\\n\")\n        && std::str::from_utf8(chunk).is_ok()\n}","typeGuard":"fn log_line_is_pipe_safe(line: &str, pending: usize) -> bool {\n    pending + line.len() + 1 <= 16_384 && line.contains('\\n')\n}","tryCatchPattern":"use std::io::Write;\nlet mut stderr = std::io::stderr();\nif let Err(e) = stderr.write_all(msg.as_bytes()) {\n    if e.kind() == std::io::ErrorKind::InvalidData {\n        // buffer exceeded: drop the message, keep the plugin alive\n        log::warn!(\"dropped oversized log message\");\n    } else { return Err(e); }\n}","preventionTips":["Always terminate log lines with \\n (prefer eprintln! over eprint!)","Flush stderr after each log call or batch; flush on UTF-8 character boundaries","Cap single log lines well below 16KiB (truncate large payloads before logging)","Never write binary or partial multibyte sequences to plugin stderr"],"tags":["plugins","wasm","logging","stderr","buffer"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}