{"record":{"id":"0b2c340334a0c486","repo":"zeroclaw-labs/zeroclaw","slug":"matrix-reason-cannot-auto-recover-because-chann","errorCode":null,"errorMessage":"matrix: {reason}\nCannot auto-recover because channels.matrix.password and channels.matrix.user-id are not both set.\nEither:\n  • configure channels.matrix.password (and user-id) so the next start can re-authenticate, or\n  • wipe the state directory manually:  rm -rf {}","messagePattern":"matrix: (.+?)\nCannot auto-recover because channels\\.matrix\\.password and channels\\.matrix\\.user-id are not both set\\.\nEither:\n  • configure channels\\.matrix\\.password \\(and user-id\\) so the next start can re-authenticate, or\n  • wipe the state directory manually:  rm -rf (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/zeroclaw-channels/src/matrix.rs","lineNumber":1504,"sourceCode":"        config: &MatrixConfig,\n        state_dir: &Path,\n        recovery_attempts: u32,\n        reason: &str,\n    ) -> Result<Client> {\n        if can_password_relogin(config) {\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                &format!(\n                    \"matrix: {reason} Auto-recovering: wiping {} and re-authenticating with password.\",\n                    state_dir.display()\n                )\n            );\n            wipe_state(state_dir)?;\n            return Box::pin(build_attempt(config, state_dir, recovery_attempts + 1)).await;\n        }\n        bail!(\n            \"matrix: {reason}\\n\\\n             Cannot auto-recover because channels.matrix.password and channels.matrix.user-id are not both set.\\n\\\n             Either:\\n  \\\n             • configure channels.matrix.password (and user-id) so the next start can re-authenticate, or\\n  \\\n             • wipe the state directory manually:  rm -rf {}\",\n            state_dir.display(),\n        );\n    }\n\n    async fn login_fresh(client: &Client, config: &MatrixConfig) -> Result<()> {\n        // Prefer password when set: it creates a server-side device matching\n        // `config.device_id`, so subsequent crypto operations don't fight with\n        // a token bound to a different device.\n        if let Some(pw) = config.password.as_deref().filter(|s| !s.is_empty()) {\n            return password_login(client, config, pw).await;\n        }\n        if config\n            .access_token","sourceCodeStart":1486,"sourceCodeEnd":1522,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/matrix.rs#L1486-L1522","documentation":"When Matrix startup hits a session failure it can auto-recover by wiping the state directory and logging in again, but re-authentication requires channels.matrix.user-id and channels.matrix.password. On an access-token-only deployment there is no way to re-login after a wipe, so instead of destroying session state it cannot rebuild, the channel refuses and reports the underlying reason plus the two remedies: add password credentials, or wipe manually.","triggerScenarios":"Starting the Matrix channel when persisted session state fails to load or validate (the {reason} prefix) while config provides access_token only - password and user-id are not both set, so the auto-wipe-and-relogin path is unavailable.","commonSituations":"Access token revoked (logout-all, password change) or session file corrupted on a headless deployment provisioned with just a token; migrating hosts with a stale state dir; initial setup where only homeserver and token were filled in.","solutions":["Set channels.matrix.user-id and channels.matrix.password, then restart: the next start wipes state and re-authenticates automatically.","Or stop the agent and wipe manually (the path is printed in the error), then restart with a fresh access token.","Keep user-id plus password configured long-term so future session corruption self-heals instead of halting the channel."],"exampleFix":"# before: token-only - no relogin possible after session corruption\n[channels.matrix]\nhomeserver = \"https://matrix.example.org\"\naccess-token = \"syt_...\"\n\n# after: recovery credentials present\n[channels.matrix]\nhomeserver = \"https://matrix.example.org\"\nuser-id = \"@bot:example.org\"\npassword = \"correct-horse-battery\"","handlingStrategy":"validation","validationCode":"// At deploy time: assert the channel can re-authenticate after a session wipe.\nfn can_auto_recover(cfg: &MatrixConfig) -> bool {\n    cfg.user_id.as_deref().is_some_and(|u| !u.trim().is_empty())\n        && cfg.password.as_deref().is_some_and(|p| !p.is_empty())\n}\nif !can_auto_recover(&config) {\n    tracing::warn!(\"matrix: no relogin credentials; a corrupted session will halt the channel until the state dir is wiped manually\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Provision user-id plus password on every long-running Matrix deployment, even when an access token is the primary auth.","Back up the state directory so manual wipes are cheap.","Rotate access tokens through a controlled restart, never by surprise mid-run.","Treat this error as a paging event: the channel stays down until a human acts."],"tags":["matrix","auth","session","state-dir","config","recovery"],"backgroundTag":"auth-session-recovery-required","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}