{"record":{"id":"e35f37f8c3595f74","repo":"risingwavelabs/risingwave","slug":"failed-to-write-char-c","errorCode":null,"errorMessage":"failed to write_char [{c}]","messagePattern":"failed to write_char \\[(.+?)\\]","errorType":"error_code","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src/utils/pgwire/src/pg_message.rs","lineNumber":797,"sourceCode":"                        for c in s.as_str().chars() {\n                            // As suggested in https://en.wikipedia.org/wiki/Tab-separated_values\n                            // we only escape \"\\t\\b\\r\\\\\"\n                            match c {\n                                '\\t' => {\n                                    buf.put_slice(b\"\\\\t\");\n                                }\n                                '\\n' => {\n                                    buf.put_slice(b\"\\\\n\");\n                                }\n                                '\\r' => {\n                                    buf.put_slice(b\"\\\\r\");\n                                }\n                                '\\\\' => {\n                                    buf.put_slice(b\"\\\\\\\\\");\n                                }\n                                _ => {\n                                    std::fmt::Write::write_char(buf, c).map_err(|_| {\n                                        Error::other(anyhow!(\"failed to write_char [{c}]\"))\n                                    })?;\n                                }\n                            }\n                        }\n                        Ok(())\n                    }\n                    match row.values() {\n                        [] => {}\n                        [first, rest @ ..] => {\n                            write_str_bytes(buf, first)?;\n\n                            for rest in rest {\n                                buf.put_u8(b'\\t');\n                                write_str_bytes(buf, rest)?;\n                            }\n                        }\n                    }\n                    buf.put_u8(b'\\n');","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/utils/pgwire/src/pg_message.rs#L779-L815","documentation":"In write_str_bytes (pg_message.rs:797), while escaping a string into the outgoing buffer, the fallback branch calls std::fmt::Write::write_char on the BytesMut-backed formatter; if the underlying write fails, the error is wrapped as Error::other(\"failed to write_char [{c}]\"). In practice this signals an internal failure while serializing a string literal into a backend message, not a client-input problem.","triggerScenarios":"Calling the message write path (FeMessage::write / serialization of a response containing a string field) when the fmt::Write impl over the byte buffer returns Err — essentially only on buffer allocation/append failure; a normal char always succeeds, so this surfaces as an internal invariant issue during response serialization.","commonSituations":"Writing error/data row responses containing unusual characters where escaping hits an unexpected branch; running out of memory while growing the response buffer; bugs in a custom writer wrapped around BytesMut.","solutions":["Reproduce with the logged character [c] and check whether the escaping logic should be handling it in an earlier branch (e.g. quote/backslash handling) rather than the fallback write_char.","Check server logs/monitoring for memory pressure or allocation failures at serialization time; a failed append to the buffer is the usual root cause.","If a custom writer or patched BytesMut wrapper is in use, verify its fmt::Write implementation never returns Err for valid chars.","This is effectively an internal invariant violation — if reproducible with normal data, file a bug with the offending character and message type."],"exampleFix":"// before: fallback may fail silently on exotic chars\nstd::fmt::Write::write_char(buf, c).map_err(|_| Error::other(anyhow!(\"failed to write_char [{c}]\")))?;\n// after: ensure capacity before writing, avoiding transient append failure\nbuf.reserve(c.len_utf8());\nstd::fmt::Write::write_char(buf, c).map_err(|_| Error::other(anyhow!(\"failed to write_char [{c}]\")))?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// serialization path\nif let Err(e) = msg.write(&mut buf).await {\n    if e.to_string().starts_with(\"failed to write_char\") {\n        log::error!(\"internal serialization failure: {}\", e);\n        // do not send the partially built buffer; reset and close\n        buf.clear();\n    }\n    return Err(e.into());\n}","preventionTips":["Reserve buffer capacity before writing large response strings to avoid append failures.","Keep BytesMut's fmt::Write implementation unmodified and well-tested.","Review the escaping branches so expected special chars are handled explicitly, not via fallback.","Treat any occurrence as a bug report trigger: capture the character and message type."],"tags":["serialization","string-escaping","internal-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}