zeroclaw-labs/zeroclaw · error · anyhow::Error
matrix: `homeserver` is required
Error message
matrix: `homeserver` is required
What it means
The Matrix channel constructor validates config up front: channels.matrix.homeserver must be a non-empty, non-whitespace string, because every SDK call (login, sync, send) needs the homeserver base URL. An empty homeserver aborts construction immediately, before any login attempt - even when an access token is configured, since a token does not imply a server.
Source
Thrown at crates/zeroclaw-channels/src/matrix.rs:3987
undecryptable_seen: Arc<TokioMutex<HashSet<OwnedEventId>>>,
/// Resolved `ack_reactions` for this Matrix instance — the
/// per-channel `MatrixConfig.ack_reactions` override falls back to
/// `[channels].ack_reactions` here at construction time, so the
/// read site doesn't need to re-resolve on every reaction.
ack_reactions: bool,
}
impl MatrixChannel {
/// Validate config and prepare the channel. The SDK Client is built lazily
/// on first `listen()` or `send()` call.
pub fn new(
config: MatrixConfig,
alias: impl Into<String>,
peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync>,
state_dir: PathBuf,
) -> Result<Self> {
if config.homeserver.trim().is_empty() {
bail!("matrix: `homeserver` is required");
}
let has_token = config
.access_token
.as_deref()
.is_some_and(|t| !t.trim().is_empty());
let has_password = config
.password
.as_deref()
.is_some_and(|p| !p.trim().is_empty());
if !has_token && !has_password {
bail!("matrix: configure either `access_token` or `password`");
}
let ack_reactions = config.ack_reactions.unwrap_or(true);
let streaming_state = streaming::State::for_stream_mode(config.stream_mode);
Ok(Self {
config: Arc::new(config),
alias: alias.into(),
peer_resolver,View on GitHub (pinned to 88bb9c8533)
Solutions
- Set channels.matrix.homeserver to the homeserver's client API base, e.g. https://matrix.example.org.
- Check the rendered config for empty values from unset environment variables - the trim check makes whitespace count as missing.
- Homeserver is mandatory in every auth mode (token or password); it cannot be omitted in favor of access_token.
- Add a config lint that fails builds when required Matrix keys are blank.
Example fix
# before [channels.matrix] access-token = "syt_..." # after [channels.matrix] homeserver = "https://matrix.example.org" access-token = "syt_..."
Defensive patterns
Strategy: validation
Validate before calling
fn homeserver_configured(cfg: &MatrixConfig) -> bool {
!cfg.homeserver.trim().is_empty()
}
assert!(homeserver_configured(&config), "channels.matrix.homeserver is required"); Type guard
fn required_homeserver(cfg: &MatrixConfig) -> Option<&str> {
let h = cfg.homeserver.trim();
(!h.is_empty()).then_some(h)
} Prevention
- Fail fast on config load: validate all required Matrix keys, homeserver first, before constructing channels.
- Render configs in strict mode so unset variables error instead of emitting empty strings.
- Keep a minimal known-good config in the repo and diff deployments against it.
When it happens
Trigger: Constructing the Matrix channel with channels.matrix.homeserver absent, empty, or whitespace-only - typically an env-var interpolation (e.g. ${MATRIX_HOMESERVER}) that produced an empty string, or a misspelled/removed config key.
Common situations: New deployment with homeserver forgotten; templating emitting "" for unset variables; config key renamed across a ZeroClaw upgrade; local dev config trimmed down too far.
Related errors
- transcription.max_audio_bytes must be greater than zero
- matrix: draft message id is empty
- matrix: {reason} Cannot auto-recover because channels.matrix
- matrix login requires either access_token or user_id+passwor
- matrix: configured channels.matrix.user-id ({configured}) do
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/ad25599601d1a7b8.
Report an issue: GitHub.