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

Missing [channels.line.{}] section

Error message

Missing [channels.line.{}] section

What it means

persist_line_paired_identity takes the live-config write lock and requires the [channels.line.<alias>] section for the webhook's alias to exist; if it is missing it bails before mutating anything. This fires when the alias embedded in the bot's runtime state (from the webhook URL) no longer matches the config file — config drift between wiring time and persistence time. The missing section name is included in the message.

Source

Thrown at crates/zeroclaw-channels/src/line.rs:258

        ::zeroclaw_log::record!(
            WARN,
            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
                .with_outcome(::zeroclaw_log::EventOutcome::Unknown)
                .with_attrs(::serde_json::json!({"user_id": user_id})),
            "paired userId not persisted (no persistence handle wired)"
        );
        return Ok(());
    };
    let normalized = user_id.trim().to_string();
    if normalized.is_empty() {
        anyhow::bail!("Cannot persist empty LINE userId");
    }
    let group_name = format!("line_{}", state.alias);
    let channel_ref = ChannelRef::new(format!("line.{}", state.alias));
    let snapshot = {
        let mut cfg = config.write();
        if !cfg.channels.line.contains_key(&state.alias) {
            anyhow::bail!("Missing [channels.line.{}] section", state.alias);
        }
        let group = cfg
            .peer_groups
            .entry(group_name)
            .or_insert_with(|| PeerGroupConfig {
                channel: channel_ref,
                ..PeerGroupConfig::default()
            });
        if group
            .external_peers
            .iter()
            .any(|p| p.as_str() == normalized)
        {
            return Ok(());
        }
        group.external_peers.push(PeerUsername::new(normalized));
        cfg.clone()
    };

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Restore (or rename back) the [channels.line.<alias>] section so it matches the alias in the running webhook URL.
  2. Restart the channel process after alias or section changes so runtime state is re-wired from current config.
  3. Keep aliases stable across environments to avoid re-pairing surprises.

Example fix

# before (config drifted: alias renamed while bot still serves old webhook)
[channels.line.main2]
channel_secret = "..."

# after
[channels.line.main]
channel_secret = "..."
Defensive patterns

Strategy: validation

Validate before calling

// At startup, prove every webhook alias has its config section
for alias in webhook_aliases() {
    anyhow::ensure!(
        config.read().channels.line.contains_key(alias),
        "webhook alias '{alias}' has no [channels.line.{alias}] section"
    );
}

Try / catch

if let Err(e) = persist_line_paired_identity(&user_id).await {
    if e.to_string().contains("Missing [channels.line.") {
        alert("config drift: restart channel after alias/config changes");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: The alias was renamed or its section removed from config while the channel was running on the old alias; a hot-reload replaced config mid-session; the channel was wired from one config and the webhook arrived against another.

Common situations: Renaming a LINE alias during environment migration, partial config deploys that drop the section, or stale runtime state after editing zeroclaw.toml without restarting the channel.

Related errors


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