{"record":{"id":"a32079661b37ed83","repo":"zeroclaw-labs/zeroclaw","slug":"matrix-not-a-room-id-or-alias-id-or-alias","errorCode":null,"errorMessage":"matrix: not a room id or alias: {id_or_alias}","messagePattern":"matrix: not a room id or alias: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/matrix.rs","lineNumber":1955,"sourceCode":"        id_or_alias: &str,\n    ) -> Result<OwnedRoomId> {\n        let (id_or_alias, normalized) = normalize_recipient(id_or_alias);\n        if normalized {\n            ::zeroclaw_log::record!(\n                WARN,\n                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)\n                    .with_outcome(::zeroclaw_log::EventOutcome::Unknown)\n                    .with_attrs(::serde_json::json!({\"id_or_alias\": id_or_alias})),\n                \"matrix: recipient contains `||`; using as the room target. Update channels.matrix or cron `delivery.to` to a plain room id/alias to silence this warning.\"\n            );\n        }\n        if id_or_alias.starts_with('!') {\n            return id_or_alias\n                .parse::<matrix_sdk::ruma::OwnedRoomId>()\n                .with_context(|| format!(\"parse room id {id_or_alias}\"));\n        }\n        if !id_or_alias.starts_with('#') {\n            bail!(\"matrix: not a room id or alias: {id_or_alias}\");\n        }\n        if let Some(id) = cache.read().await.get(id_or_alias) {\n            return Ok(id.clone());\n        }\n        let alias: &RoomAliasId = id_or_alias\n            .try_into()\n            .with_context(|| format!(\"parse room alias {id_or_alias}\"))?;\n        let resp = client\n            .resolve_room_alias(alias)\n            .await\n            .with_context(|| format!(\"resolve room alias {id_or_alias}\"))?;\n        cache\n            .write()\n            .await\n            .insert(id_or_alias.to_string(), resp.room_id.clone());\n        Ok(resp.room_id)\n    }\n}","sourceCodeStart":1937,"sourceCodeEnd":1973,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/matrix.rs#L1937-L1973","documentation":"resolve_room accepts exactly two recipient shapes: room ids starting with '!' (parsed locally) and room aliases starting with '#' (resolved via the homeserver behind a cache). Anything else - user ids starting with '@', bare room names, URLs - is rejected up front. Note normalize_recipient first strips a '||'-suffixed form with a warning, so the value echoed in the error is the bare recipient that failed the prefix check.","triggerScenarios":"Calling any send or resolve path with a recipient that starts with neither '!' nor '#': '@user:example.org' (a user id), 'ops-room' (bare name), or a pasted URL - sourced from channels.matrix config, cron delivery.to, or an upstream message's channel field.","commonSituations":"Confusing a Matrix user id with a room id; pasting a room's display name instead of its canonical alias; cron or delivery config holding '#ops' without the homeserver suffix; peer list entries that were never canonicalized.","solutions":["Use the full alias form #room:example.org or the opaque room id form !xxxx:example.org.","Copy the canonical value from a Matrix client's room settings (room address or internal room id).","Fix the config key that produced the bad recipient - it is echoed verbatim in the error.","If you meant to DM a user, create or join a room with them first and use that room's id or alias."],"exampleFix":"# before: cron delivery target is a user id\n[cron.check-in]\ndelivery.to = \"@alice:example.org\"\n\n# after: use a room alias (or room id)\ndelivery.to = \"#zeroclaw-ops:example.org\"","handlingStrategy":"validation","validationCode":"fn is_matrix_room_ref(recipient: &str) -> bool {\n    let s = recipient.trim();\n    s.starts_with('!') || s.starts_with('#')\n}\n\nfor peer in peer_list {\n    assert!(is_matrix_room_ref(&peer), \"recipient {peer} is not a room id (!...) or alias (#room:server)\");\n}","typeGuard":"fn as_room_id_or_alias(s: &str) -> Option<&str> {\n    let t = s.trim();\n    (t.starts_with('!') || t.starts_with('#')).then_some(t)\n}","tryCatchPattern":null,"preventionTips":["Canonicalize every configured peer and cron delivery target to a full alias with the homeserver suffix at config-load time.","Reject '@'-prefixed values in config lint - DM-style user ids are the classic copy-paste mistake.","Log the normalized recipient list at startup so the exact resolution inputs are reviewable."],"tags":["matrix","room-id","alias","recipient","validation"],"backgroundTag":"invalid-room-identifier","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}