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

gateway registration failed ({status}): {err}

Error message

gateway registration failed ({status}): {err}

What it means

DingTalkChannel's register_connection POSTs clientId/clientSecret plus a CALLBACK subscription for /v1.0/im/bot/messages/get to https://api.dingtalk.com/v1.0/gateway/connections/open (Stream Mode). Any non-2xx becomes this error with the status and body. Both listen() startup and health_check() route through it, so credential or endpoint problems surface here first, before any WebSocket is opened.

Source

Thrown at crates/zeroclaw-channels/src/dingtalk.rs:130

            "subscriptions": [
                {
                    "type": "CALLBACK",
                    "topic": DINGTALK_BOT_CALLBACK_TOPIC,
                }
            ],
        });

        let resp = self
            .http_client()
            .post("https://api.dingtalk.com/v1.0/gateway/connections/open")
            .json(&body)
            .send()
            .await?;

        if !resp.status().is_success() {
            let status = resp.status();
            let err = resp.text().await.unwrap_or_default();
            anyhow::bail!("gateway registration failed ({status}): {err}");
        }

        let gw: GatewayResponse = resp.json().await?;
        Ok(gw)
    }
}

impl ::zeroclaw_api::attribution::Attributable for DingTalkChannel {
    fn role(&self) -> ::zeroclaw_api::attribution::Role {
        ::zeroclaw_api::attribution::Role::Channel(
            ::zeroclaw_api::attribution::ChannelKind::DingTalk,
        )
    }
    fn alias(&self) -> &str {
        &self.alias
    }
}

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Decode the status/body in the message — DingTalk returns a specific errorCode/message (e.g. invalid clientSecret)
  2. Re-copy Client ID and Client Secret from the DingTalk Open Platform app into [channels.dingtalk.<alias>]
  3. Confirm the app has the bot/message-receive capability and Stream Mode enabled
  4. For EU apps the endpoint must be api.dingtalk.eu — currently hardcoded, so use an international app or patch the URL
  5. Remove or verify proxy_url if a proxy intercepts the registration POST
Defensive patterns

Strategy: validation

Validate before calling

// register_connection is what health_check exercises:
if !dingtalk_channel.health_check().await {
    // gateway registration failed — fix client_id/client_secret/region before listen()
}

Try / catch

if let Err(e) = channel.listen(tx).await {
    if e.to_string().contains("gateway registration failed") {
        // credential/endpoint problem: reconnect loops will keep failing until config is fixed
    }
}

Prevention

When it happens

Trigger: Invalid or rotated clientSecret; clientId of an app whose bot capability is not enabled; region mismatch — the code hardcodes api.dingtalk.com while EU apps must use api.dingtalk.eu; server IP not on the app allowlist; app not published/approved so Stream Mode is refused; per-channel proxy (build_channel_proxy_client) mangling the POST.

Common situations: Secret regenerated in the DingTalk developer console while config still holds the old one; EU-hosted app against the international host; corporate proxy blocking api.dingtalk.com; sandbox apps without stream permission.

Related errors


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