Skip to content

DingTalk Connection Troubleshooting ​

This guide focuses on startup-time DingTalk Stream connection failures, especially cases that only show 400 during plugin initialization.

What HTTP 400 Usually Means ​

For DingTalk Stream startup, HTTP 400 usually means DingTalk accepted the request and rejected its contents. It is not the same as generic network failures such as:

  • DNS resolution failure
  • TCP timeout
  • TLS handshake failure
  • proxy or firewall drops before the request reaches DingTalk

That distinction matters because:

  • 400 often points to credentials, app state, request shape, or platform-side validation.
  • timeout/TLS/DNS failures point to local network, proxy, or outbound access issues.

First Step: Run the Minimal Connection Check ​

These scripts only test:

POST https://api.dingtalk.com/v1.0/gateway/connections/open

They do not test the later WebSocket handshake. That is intentional: the first goal is to separate connections/open failures from later WSS/proxy failures.

macOS / Linux ​

bash
bash scripts/dingtalk-connection-check.sh --client-id <clientId> --client-secret <clientSecret>

Or read from OpenClaw config:

bash
bash scripts/dingtalk-connection-check.sh --config ~/.openclaw/openclaw.json

For a multi-account setup:

bash
bash scripts/dingtalk-connection-check.sh --config ~/.openclaw/openclaw.json --account-id main

Windows PowerShell ​

powershell
pwsh -File scripts/dingtalk-connection-check.ps1 -ClientId <clientId> -ClientSecret <clientSecret>

Or read from OpenClaw config:

powershell
pwsh -File scripts/dingtalk-connection-check.ps1 -Config ~/.openclaw/openclaw.json

For a multi-account setup:

powershell
pwsh -File scripts/dingtalk-connection-check.ps1 -Config ~/.openclaw/openclaw.json -AccountId main

Credential Resolution Rules ​

Both scripts follow the same order:

  1. explicit credentials passed by CLI
  2. config file passed with --config / -Config
  3. default ~/.openclaw/openclaw.json

Config lookup rules:

  • default account: channels.dingtalk.clientId / channels.dingtalk.clientSecret
  • specific account: channels.dingtalk.accounts.<accountId>

This is important when troubleshooting multi-account setups: make sure the script and the running plugin are using the same account.

How to Read the Output ​

Example success output:

text
DingTalk connection check
credential_source=account:main
config_path=/Users/you/.openclaw/openclaw.json
account_id=main
client_id=ding...1234
http_status=200
response={"endpoint":"wss://wss-open-connection.dingtalk.com:443/connect","ticket":"7724...aee6"}
endpoint=wss://wss-open-connection.dingtalk.com:443/connect
ticket=7724...aee6

Example failure output:

text
DingTalk connection check
credential_source=default
config_path=/Users/you/.openclaw/openclaw.json
account_id=
client_id=ding...1234
http_status=400
response={"code":"invalidParameter","message":"ua invalid","requestId":"abc123"}

Notes:

  • secrets are masked by design
  • ticket is masked by design
  • endpoint is safe to share in normal issue reports

Interpreting the Result ​

Case 1: connections/open returns 400 ​

Likely causes:

  • wrong clientId / clientSecret
  • app state problem in DingTalk platform
  • unsupported or rejected request payload
  • app not published, bot capability missing, or Stream mode not enabled

Check these first:

  • DingTalk app is an internal enterprise app
  • DingTalk Console → Version Management → Published → Version Details: Visibility Scope is set to "All employees"
  • Ensure there is a published version (not draft) for the internal app/robot
  • robot capability is enabled
  • message receive mode is Stream mode
  • current app version is published
  • the credentials in the script match the actual plugin runtime config

Case 2: connections/open returns 200, but plugin startup still fails ​

This is the most important split.

If connections/open succeeds, then:

  • the credentials are at least good enough for the open call
  • basic HTTPS reachability to api.dingtalk.com is working
  • the remaining problem is more likely in the later WebSocket phase or in an environment difference between the script and the plugin runtime

Check next:

  • corporate proxy or gateway interfering with WSS
  • outbound access to wss-open-connection.dingtalk.com:443
  • TLS interception / SSL MITM products
  • Node runtime environment variables like HTTP_PROXY, HTTPS_PROXY, NO_PROXY
  • whether the plugin process and the shell script are truly running on the same machine / container / network path

Example websocket-stage log snippet:

text
[main] Failed to establish connection: Unexpected server response: 400 [DingTalk][ConnectionError][connect.websocket] endpoint=wss://wss-open-connection.dingtalk.com:443/connect Likely websocket/proxy/WSS issue after connections/open succeeded See docs/user/troubleshooting/connection.en.md or run scripts/dingtalk-connection-check.*

Case 3: no HTTP status / transport failure ​

If the script cannot produce a real HTTP status, investigate:

  • DNS resolution
  • outbound firewall rules
  • proxy configuration
  • TLS certificate trust

What the Plugin Now Logs ​

Startup failures now try to include more detail when DingTalk returns a structured error response, for example:

  • HTTP status
  • connection stage
  • DingTalk code
  • DingTalk message
  • request ID
  • sanitized error payload

Stage meanings ​

  • connect.open: failure happened while requesting POST /v1.0/gateway/connections/open
  • connect.websocket: connections/open already succeeded, but the later WebSocket connection still failed

This split is useful because:

  • connect.open usually points you back to credentials, app state, Stream mode setup, or DingTalk request validation.
  • connect.websocket points much more strongly to WSS reachability, proxy behavior, TLS interception, or corporate gateway policy.

If you see connect.websocket together with an endpoint like wss://wss-open-connection.dingtalk.com/..., prioritize checking:

  • outbound WSS access on port 443
  • proxy Upgrade / WebSocket support
  • SSL MITM / security products
  • whether the plugin process is running behind a different proxy path than your manual shell test

Required endpoints to reach:

  • https://api.dingtalk.com:443 (open stage)
  • wss://wss-open-connection.dingtalk.com:443 (websocket stage)

User-side settings checklist (DingTalk Console) ​

  • Enterprise internal app/robot has a published version (not only in draft)
  • Version Management → Published → Version Details → Visibility Scope: All employees
  • Robot capability is enabled
  • Message receive mode: Stream mode

If you open an issue, include:

  • the plugin startup error line
  • the output of one of the connection-check scripts
  • whether you are using default account config or a named accountId
  • scripts/dingtalk-connection-check.sh
  • scripts/dingtalk-connection-check.ps1
  • src/connection-manager.ts
  • README.md Proxy notes:
  • Scripts inherit HTTP_PROXY / HTTPS_PROXY / NO_PROXY from your environment.
  • For WebSocket (WSS) testing, ensure your proxy/gateway supports Upgrade and TLS pass-through.