Skip to content

Plugin loader: silent failures on legacy/invalid plugin contracts cost hours of debugging #78301

Description

@lawong888

While debugging why @tencent-weixin/[email protected] was failing on a 2026.5.4 host, I hit two cases where the plugin loader silently tolerates plugin-authoring bugs that surface much later as opaque runtime errors. Both could have been caught at plugin load time with a clear message naming the plugin and the contract violated.

This is a request for better diagnostics — not for relaxing the underlying defenses, which are correct.

Case 1 — Strict undici dispatcher rejects manual Content-Length, but the cause is buried

OpenClaw installs a hardened global undici dispatcher (visible via ensureGlobalUndiciEnvProxyDispatcher / fetchWithSsrFGuard in openclaw/plugin-sdk/infra-runtime) that correctly rejects plugin-supplied Content-Length headers with UND_ERR_INVALID_ARG: invalid content-length header. This is good — manual Content-Length enables request-smuggling vectors when the value drifts from the actual transmitted bytes.

Problem: the rejection bubbles up as a generic TypeError: fetch failed. The actual cause is only visible if the plugin inspects err.cause. Most plugin code does String(err) and the signal is lost. End result for the operator: a silent restart loop with no actionable log line.

Repro (real): the Tencent plugin's dist/src/api/api.js line 164 manually sets Content-Length. Every API call (getUpdates, login, send) fails synchronously. Surface symptom is Failed to start login: TypeError: fetch failed and a Weixin runtime initialization timeout loop. The actual root cause took bisecting through the plugin's import graph to find — the openclaw SDK import was what flipped fetch behavior.

Suggested improvement: in fetchWithRuntimeDispatcher / fetchWithSsrFGuard (or wherever plugin requests funnel through), strip and warn on plugin-supplied Content-Length with a one-time deprecation log per plugin:

[plugins] [openclaw-weixin] dropping plugin-supplied Content-Length header on POST /ilink/bot/get_bot_qrcode — undici computes this itself. Manual values risk request smuggling. See <docs link>.

This converts a hard failure into a soft signal that names the offending plugin.

Case 2 — Plugins without "runtime" in manifest get no runtime injection and no warning

@openclaw/[email protected] declares in its plugin manifest:

"runtime": { "specifier": "./runtime-api.js", "exportName": "setWhatsAppRuntime" }

…and the host correctly calls setWhatsAppRuntime on load.

@tencent-weixin/[email protected] does not declare runtime in its openclaw.plugin.json or package.json#openclaw. Its register(api) reads api.runtime (the legacy contract) and only calls setWeixinRuntime(api.runtime) when truthy. On 2026.5.4 it isn't, so pluginRuntime stays null, waitForWeixinRuntime times out at 10s, and the channel enters a permanent restart loop with Weixin runtime initialization timeout — logged by the plugin, not the host.

The loader is silent about this mismatch. There's no host-side diagnostic at plugin-load time that says this plugin uses the legacy runtime contract; runtime injection skipped.

Suggested improvement: after calling register(api), if the plugin's manifest doesn't declare runtime AND the host didn't pass runtime into api, emit a one-time deprecation warning per plugin:

[plugins] [openclaw-weixin] no `runtime` declaration in openclaw.plugin.json; runtime injection skipped. Plugins using register({api: {runtime}}) must migrate to manifest-declared runtime. See <migration doc>.

Bonus — Migration guide

A Plugin author's migration guide: 2026.4.x → 2026.5.x linked from the relevant sections of plugin-sdk would close the loop. The Tencent plugin (Tencent/openclaw-weixin on GitHub) hasn't migrated, possibly because the migration was never visible to them. A short section showing the before/after for runtime: {specifier, exportName} would help every external plugin author.

Environment

  • OpenClaw: 2026.5.4
  • Node: 22.22.2
  • OS: Ubuntu 24.04 arm64 (Raspberry Pi 5)
  • Plugin context: @tencent-weixin/[email protected] (will file the actual plugin bugs at Tencent/openclaw-weixin separately)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions