zeroclaw-labs/zeroclaw · error
[channels.lark.{alias}] has use_feishu=false but cron channe
Error message
[channels.lark.{alias}] has use_feishu=false but cron channel="feishu.{alias}"; use channel="lark.{alias}" or set use_feishu=true What it means
Both "lark.<alias>" and "feishu.<alias>" resolve through the single [channels.lark.<alias>] config table (the single source of truth for both names). This bail fires when the cron channel says feishu but that table has use_feishu = false: that combination is treated as a typo and hard-fails by design. It is asymmetric on purpose — "lark" with use_feishu = true only logs a warning and still delivers via fallback construction.
Source
Thrown at crates/zeroclaw-channels/src/orchestrator/mod.rs:12941
// cron alias the user wrote.
let lk = config.channels.lark.get(alias).ok_or_else(|| {
::zeroclaw_log::record!(
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure),
&format!(
"[channels.lark.{alias}] not configured (cron channel \"{channel_type}.{alias}\")"
)
);
anyhow::Error::msg(format!(
"[channels.lark.{alias}] not configured (cron channel \"{channel_type}.{alias}\")"
))
})?;
// Asymmetric by design: "feishu"+use_feishu=false is a typo
// (hard fail). "lark"+use_feishu=true is a soft compat path
// (warn but still deliver via fallback construction).
if channel_type == "feishu" && !lk.use_feishu {
anyhow::bail!(
"[channels.lark.{alias}] has use_feishu=false but cron channel=\"feishu.{alias}\"; \
use channel=\"lark.{alias}\" or set use_feishu=true"
);
}
if channel_type == "lark" && lk.use_feishu {
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
.with_outcome(::zeroclaw_log::EventOutcome::Unknown),
&format!(
"cron channel=\"lark.{alias}\" with [channels.lark.{alias}] use_feishu=true \
falls back to one-shot channel construction; prefer channel=\"feishu.{alias}\" \
to reuse the live Feishu handle from start_channels"
)
);
}
let peers = config.channel_external_peers("lark", alias);
let peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync> =View on GitHub (pinned to 88bb9c8533)
Solutions
- If the endpoint really is Lark, change the cron to channel = "lark.<alias>"
- If the endpoint really is Feishu, set use_feishu = true under [channels.lark.<alias>]
- Audit every cron/routing entry that uses the feishu. prefix after any use_feishu change
Example fix
# before [channels.lark.work] app_id = "cli_x" use_feishu = false [cron.report] channel = "feishu.work" # after [cron.report] channel = "lark.work" # endpoint is Lark; keep use_feishu = false
Defensive patterns
Strategy: validation
Validate before calling
// Before scheduling/delivering, enforce the lark/feishu naming rule:
fn check_lark_ref(config: &Config, channel: &str) -> anyhow::Result<()> {
let (kind, alias) = channel.split_once('.').context("channel must be <type>.<alias>")?;
if let Some(lk) = config.channels.lark.get(alias) {
if kind.eq_ascii_lowercase("feishu") && !lk.use_feishu {
anyhow::bail!("feishu.{alias} requires use_feishu=true; use lark.{alias} instead");
}
}
Ok(())
} Try / catch
match deliver_announcement(&cfg, "feishu.work", &target, thread, &out).await {
Err(e) if e.to_string().contains("use_feishu=false") => {
// Deterministic config mismatch: rewrite the cron channel or flip use_feishu; do not retry.
}
rest => rest?,
} Prevention
- Pick one naming convention per deployment and lint crons against it
- When flipping use_feishu, grep all cron/routing entries for the other prefix in the same change
- Remember the asymmetry: feishu+false hard-fails, lark+true only warns
When it happens
Trigger: Cron channel = "feishu.work" while [channels.lark.work] has use_feishu = false (or unset when false is the default); deliver_announcement hits the mismatch check right after resolving the config table.
Common situations: Copy-pasting a channel ref from a Feishu-based example into a Lark-endpoint deployment (or vice versa); flipping use_feishu after crons were already written with the feishu. prefix; team confusion because both names target the same config table.
Related errors
- send failed {context}: status={status}, body={body}
- send failed {context}: code={code}, body={body}
- WS endpoint failed: code={} msg={}
- tenant_access_token request failed: status={status}, body={d
- tenant_access_token failed: {msg}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/1e09c2055313e4cd.
Report an issue: GitHub.