{"record":{"id":"79e37329af8976e0","repo":"zeroclaw-labs/zeroclaw","slug":"matrix-configured-message-max-bytes-cannot-contai","errorCode":null,"errorMessage":"matrix: configured message_max_bytes cannot contain a threaded reply event","messagePattern":"matrix: configured message_max_bytes cannot contain a threaded reply event","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/matrix.rs","lineNumber":3618,"sourceCode":"                        ERROR,\n                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)\n                            .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                            .with_attrs(::serde_json::json!({\"error\": format!(\"{}\", e)})),\n                        \"make_reply_event failed\"\n                    );\n                    anyhow::Error::msg(format!(\"make_reply_event failed: {e}\"))\n                })?;\n            let Some(max_bytes) = message_max_bytes else {\n                break event;\n            };\n            let actual =\n                serde_json::to_vec(&event).map_or(usize::MAX, |serialized| serialized.len());\n            if actual <= max_bytes {\n                break event;\n            }\n            let next = next_prefix_after_oversize(&candidate, actual, max_bytes);\n            if next.len() == candidate.len() {\n                anyhow::bail!(\n                    \"matrix: configured message_max_bytes cannot contain a threaded reply event\"\n                );\n            }\n            candidate = next.to_string();\n        };\n        ctx_mod::mark_seen(threads_seen, anchor).await;\n        let resp = room.send(reply_event).await?;\n        Ok(resp.response.event_id)\n    }\n\n    pub(super) async fn edit(\n        client: &Client,\n        room_id: &str,\n        event_id: &OwnedEventId,\n        text: &str,\n        message_max_bytes: Option<usize>,\n    ) -> Result<String> {\n        let room = client","sourceCodeStart":3600,"sourceCodeEnd":3636,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/matrix.rs#L3600-L3636","documentation":"send_threaded_reply enforces the configured message_max_bytes on the fully serialized Matrix event, shrinking the reply body via next_prefix_after_oversize in a loop until the event fits. When the shrinker can no longer cut anything (next.len() == candidate.len()) and the event still exceeds the cap, the budget is below the floor of any valid threaded-reply event - the JSON envelope plus reply/thread relation metadata alone costs more than message_max_bytes - so it aborts rather than emit an oversized or structurally invalid event.","triggerScenarios":"reply_in_thread active with a message_max_bytes so small that even the shortest candidate body cannot make the serialized threaded reply event fit: the shrink loop exhausts on the first (or an early) iteration.","commonSituations":"Tightening message_max_bytes to suppress long bot output and accidentally crossing below the threaded-event framing floor; reply fallbacks (the quoted parent message) inflating every reply event; SDK/server versions with larger event envelopes than the budget assumed.","solutions":["Raise channels.matrix.message_max_bytes - the threaded event carries the serialized envelope plus reply/thread relation fields, so the budget must exceed that floor by the intended body size; increase in steps until the send succeeds.","If the byte budget is a hard requirement, disable threaded replies for this room or channel so plain events (smaller envelope) are sent.","Shorten fixed serialized contributors such as the quoted parent text where possible."],"exampleFix":"# before\n[channels.matrix]\nmessage_max_bytes = 512\n\n# after\n[channels.matrix]\nmessage_max_bytes = 4096","handlingStrategy":"validation","validationCode":"// Startup probe: measure the serialized floor of a minimal threaded reply\n// and reject budgets below it before any message is attempted.\nlet probe = room\n    .make_reply_event(\n        RoomMessageEventContentWithoutRelation::new(MessageType::Text(\n            TextMessageEventContent::plain(\"\"),\n        )),\n        Reply {\n            event_id: anchor.clone(),\n            enforce_thread: EnforceThread::Threaded(ReplyWithinThread::No),\n            add_mentions: AddMentions::No,\n        },\n    )\n    .await?;\nlet floor = serde_json::to_vec(&probe)?.len();\nif let Some(max) = config.message_max_bytes {\n    anyhow::ensure!(max > floor, \"message_max_bytes {max} is below the threaded-event floor {floor}\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Budget for event framing (envelope plus reply/thread relation fields) on top of visible body text when setting message_max_bytes.","Test threaded sends under the configured budget in CI.","Raise the budget before enabling threading on rooms with long parent messages, which enlarge reply fallbacks."],"tags":["matrix","message-size","threading","config","send"],"backgroundTag":"message-size-limit-exceeded","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}