zeroclaw-labs/zeroclaw · error · anyhow::Error
channel does not support room creation
Error message
channel does not support room creation
What it means
check() (src/commands/update.rs:119) GETs the GitHub releases API — https://api.github.com/repos/zeroclaw-labs/zeroclaw/releases/latest, or /releases/tags/v<tag> when a --version is pinned — with an unauthenticated client (UA zeroclaw/<version>, 15s timeout) and bails on any non-2xx status, echoing the raw status. Reachability failures are a different error ("failed to reach GitHub releases API"); this one means GitHub answered but refused. Both `zeroclaw update` and update checks run through this function.
Source
Thrown at crates/zeroclaw-api/src/channel.rs:904
/// Unpin a previously pinned message.
async fn unpin_message(&self, _channel_id: &str, _message_id: &str) -> anyhow::Result<()> {
Ok(())
}
/// Redact (delete) a message from the channel.
async fn redact_message(
&self,
_channel_id: &str,
_message_id: &str,
_reason: Option<String>,
) -> anyhow::Result<()> {
Ok(())
}
/// Create a new platform room/conversation when the channel supports it.
async fn create_room(&self, _options: &RoomCreationOptions) -> anyhow::Result<String> {
anyhow::bail!("channel does not support room creation")
}
/// Invite a user to an existing platform room/conversation.
async fn invite_user(&self, _room_id: &str, _user_id: &str) -> anyhow::Result<()> {
anyhow::bail!("channel does not support room invites")
}
/// Request interactive tool-call approval from the channel operator.
///
/// Returns `Ok(Some(response))` when the operator answers within the
/// channel's configured `approval_timeout_secs`; timeouts surface as
/// `Deny`. Returns `Ok(None)` only for channels that do not implement
/// the prompt at all — the caller falls back to its default policy
/// (typically auto-deny).
async fn request_approval(
&self,
_recipient: &str,
_request: &ChannelApprovalRequest,View on GitHub (pinned to 88bb9c8533)
Solutions
- If 403: you hit the unauthenticated rate limit — wait for the window to reset and retry (curl -I the API URL and check x-ratelimit-reset)
- If 404 with --version: verify the tag exists on the releases page; drop --version to fetch latest
- Check https://www.githubstatus.com and your proxy/HTTPS_PROXY environment for 5xx or interception
- Retry `zeroclaw update --check` after a minute — transient statuses clear on their own
Example fix
// before
let info = update::check(None).await?; // dies on first 403 rate-limit
// after
let mut backoff = 30;
let info = loop {
match update::check(None).await {
Ok(i) => break i,
Err(e) if e.to_string().contains("GitHub API returned 403") => {
tokio::time::sleep(std::time::Duration::from_secs(backoff)).await;
backoff *= 2;
}
Err(e) => return Err(e),
}
}; Defensive patterns
Strategy: retry
Validate before calling
// Cheap preflight: confirm the releases API answers 200 before running update.
async fn releases_api_ok() -> bool {
reqwest::Client::new()
.get("https://api.github.com/repos/zeroclaw-labs/zeroclaw/releases/latest")
.header("User-Agent", "preflight")
.send()
.await
.map(|r| r.status().is_success())
.unwrap_or(false)
} Try / catch
match update::check(version).await {
Err(e) => {
let msg = e.to_string();
if msg.contains("403") || msg.contains("429") {
// Rate limited: sleep out the window (check x-ratelimit-reset), then retry once.
} else if msg.contains("404") {
// Permanent: the pinned tag does not exist — fail fast with a clear message.
} else if msg.contains("5") /* 5xx */ {
// Transient GitHub outage: retry with backoff.
}
}
ok => ok,
} Prevention
- Do not poll the unauthenticated releases API in tight loops (60 req/h per IP)
- Cache UpdateInfo results and re-check at most every few hours
- Validate user-supplied --version tags against the releases page before invoking update
When it happens
Trigger: `zeroclaw update [--check]` or `zeroclaw update --version <v>` when GitHub returns 403 (unauthenticated rate limit of 60 req/h per IP exceeded), 404 (pinned tag does not exist or no releases published), or a 5xx outage. Also triggered by any caller of update::check().
Common situations: Shared CI runner or NAT egress IP that exhausted the unauthenticated rate limit; typo'd or yanked --version tag; GitHub incident; proxies that answer with 4xx on behalf of GitHub.
Related errors
- elicitation returned unknown choice const: {s}
- purge_namespace not supported by this memory backend
- Discord send message failed ({status}): {err}
- comment reply failed ({status}): {body}
- DM failed ({status}): {body}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/e72a04e91b9ed41d.
Report an issue: GitHub.