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

matrix login requires either access_token or user_id+passwor

Error message

matrix login requires either access_token or user_id+password

What it means

Matrix login dispatches purely on config: a non-empty (trimmed) access_token selects token login, otherwise user-id + password are used. If neither combination is present, login bails before any network call. It is a configuration-completeness error: one of access_token, or both user-id and password, must be non-empty.

Source

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

            state_dir.display(),
        );
    }

    async fn login_fresh(client: &Client, config: &MatrixConfig) -> Result<()> {
        // Prefer password when set: it creates a server-side device matching
        // `config.device_id`, so subsequent crypto operations don't fight with
        // a token bound to a different device.
        if let Some(pw) = config.password.as_deref().filter(|s| !s.is_empty()) {
            return password_login(client, config, pw).await;
        }
        if config
            .access_token
            .as_deref()
            .is_some_and(|t| !t.is_empty())
        {
            return access_token_login(client, config).await;
        }
        bail!("matrix login requires either access_token or user_id+password")
    }

    async fn password_login(client: &Client, config: &MatrixConfig, password: &str) -> Result<()> {
        let user_id = config
            .user_id
            .clone()
            .filter(|s| !s.is_empty())
            .ok_or_else(|| {
                ::zeroclaw_log::record!(
                    WARN,
                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
                        .with_outcome(::zeroclaw_log::EventOutcome::Failure),
                    "matrix.user_id is required for password login"
                );
                anyhow::Error::msg("matrix.user_id is required for password login")
            })?;
        let mut login = client
            .matrix_auth()

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Set a valid channels.matrix.access_token, or set both channels.matrix.user-id and channels.matrix.password.
  2. Values are trimmed: a whitespace-only token counts as missing - delete the blank keys entirely.
  3. Verify env expansion (e.g. ${MATRIX_TOKEN}) actually resolves in the deployment environment.
  4. Run a config lint at deploy time so missing credentials fail the pipeline, not the runtime.

Example fix

# before
[channels.matrix]
homeserver = "https://matrix.example.org"

# after
[channels.matrix]
homeserver = "https://matrix.example.org"
user-id = "@bot:example.org"
password = "correct-horse-battery"
Defensive patterns

Strategy: validation

Validate before calling

fn matrix_auth_complete(cfg: &MatrixConfig) -> bool {
    let token = cfg.access_token.as_deref().is_some_and(|t| !t.trim().is_empty());
    let password = cfg.user_id.as_deref().is_some_and(|u| !u.trim().is_empty())
        && cfg.password.as_deref().is_some_and(|p| !p.is_empty());
    token || password
}

assert!(matrix_auth_complete(&config), "channels.matrix needs access_token or user-id+password");

Type guard

enum MatrixAuth<'a> { Token(&'a str), Password(&'a str, &'a str), Missing }

fn classify_auth(cfg: &MatrixConfig) -> MatrixAuth<'_> {
    if let Some(t) = cfg.access_token.as_deref() {
        if !t.trim().is_empty() {
            return MatrixAuth::Token(t);
        }
    }
    match (cfg.user_id.as_deref(), cfg.password.as_deref()) {
        (Some(u), Some(p)) if !u.trim().is_empty() && !p.is_empty() => MatrixAuth::Password(u, p),
        _ => MatrixAuth::Missing,
    }
}

Prevention

When it happens

Trigger: Starting or constructing the Matrix channel when channels.matrix has no access_token and lacks the user-id + password pair, or has only one of the two password fields.

Common situations: Half-finished migration from token auth to password auth (password set, user-id forgotten); env-var interpolation producing empty strings; first-time setup that skipped credentials; config keys renamed after an upgrade.

Related errors


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