zeroclaw-labs/zeroclaw · critical · anyhow::Error

matrix: corruption recovery looped — aborting to avoid an in

Error message

matrix: corruption recovery looped — aborting to avoid an infinite restart cycle. Wipe ~/.zeroclaw/state/matrix/ manually and restart.

What it means

Matrix client startup wraps session loading in bounded auto-recovery: corrupted persisted state triggers a wipe of the state directory plus a fresh login, retried via build_attempt with a recovery_attempts counter. Anything above 1 aborts with this message - a hard recursion bound so a wipe-then-relogin cycle cannot loop forever. Seeing it means corruption (or a login failure indistinguishable from it) recurred even after the automatic wipe already ran once.

Source

Thrown at crates/zeroclaw-channels/src/matrix.rs:1329

        blob: &session::SessionBlob,
    ) -> bool {
        let Some(want) = config.user_id.as_deref().filter(|s| !s.is_empty()) else {
            return false;
        };
        if !want.contains(':') {
            return false;
        }
        want != blob.user_id.as_str()
    }

    async fn build_attempt(
        config: &MatrixConfig,
        state_dir: &Path,
        recovery_attempts: u32,
    ) -> Result<Client> {
        // Hard recursion bound: at most one auto-wipe + relogin cycle per call.
        if recovery_attempts > 1 {
            bail!(
                "matrix: corruption recovery looped — aborting to avoid an infinite restart cycle. \
                 Wipe ~/.zeroclaw/state/matrix/ manually and restart."
            );
        }

        let saved = session::load(state_dir)?;

        // A saved session that belongs to a different account would run this
        // channel block as the wrong Matrix identity. Wipe and re-login fresh
        // under the configured account instead of impersonating.
        if let Some(blob) = saved.as_ref()
            && saved_session_is_foreign(config, blob)
        {
            return recover_or_bail(
                config,
                state_dir,
                recovery_attempts,
                &format!(

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Stop the agent and wipe the state directory manually, as the message says: rm -rf ~/.zeroclaw/state/matrix/ , then restart.
  2. If it recurs after a manual wipe, check disk health and free space on the volume backing the state dir - a failing or full disk re-corrupts every new session.
  3. Verify the homeserver is reachable and credentials are valid so the fresh login after the wipe succeeds (set channels.matrix.user-id and password).
  4. On containers, ensure the state volume is persistent and writable, and the clock is NTP-synced.
Defensive patterns

Strategy: fallback

Try / catch

match build_matrix_client(&config, &state_dir, 0).await {
    Ok(client) => client,
    Err(err) if err.to_string().contains("corruption recovery looped") => {
        // escalate to the operator instead of restarting: a naive supervisor
        // would re-trigger the same wipe/relogin loop
        shutdown_with_alert("matrix state dir needs manual wipe", &state_dir);
        return Err(err);
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Starting the Matrix channel when the persisted session under the state_dir is corrupted; build_attempt wipes state and re-logins (recovery_attempts 0 to 1), and the freshly created session fails or corrupts again, so the recursive attempt sees recovery_attempts > 1.

Common situations: Disk/filesystem problems or a full disk repeatedly truncating session files; a homeserver that keeps invalidating the new session (forced password change, security policy); containers remounting a broken or non-persistent state volume; clock skew making fresh sessions look invalid.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/5021282d2d72fbb6. Report an issue: GitHub.