Skip to content

fix: skip bundled plugin load failures in status flows#70326

Open
jason-allen-oneal wants to merge 10 commits intoopenclaw:mainfrom
jason-allen-oneal:fix/status-bundled-plugin-load-failure
Open

fix: skip bundled plugin load failures in status flows#70326
jason-allen-oneal wants to merge 10 commits intoopenclaw:mainfrom
jason-allen-oneal:fix/status-bundled-plugin-load-failure

Conversation

@jason-allen-oneal
Copy link
Copy Markdown

@jason-allen-oneal jason-allen-oneal commented Apr 22, 2026

Summary

  • Catch bundled plugin factory failures when resolving bundled channel plugins/setup plugins
  • Keep status/read-only channel discovery alive when a bundled setup entry hits a missing runtime dependency
  • Add regression coverage for the bundled setup failure case

Documentation

  • Added an Unreleased changelog entry describing the status/read-only bundled plugin load failure fix.

Verification

  • pnpm vitest run -c test/vitest/vitest.channels.config.ts src/channels/plugins/bundled.shape-guard.test.ts src/channels/plugins/read-only.test.ts
  • pnpm build

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 22, 2026

Greptile Summary

This PR adds error resilience to bundled plugin loading by adding catch blocks to both getBundledChannelPluginForRoot and getBundledChannelSetupPluginForRoot, so that a missing runtime dependency in a bundled plugin factory no longer propagates and kills the entire status/read-only channel discovery flow. The fix is accompanied by a regression test that verifies the setup failure case is swallowed and returns undefined.

The implementation integrates cleanly with the existing flatMap filtering in listBundledChannelPlugins() and listBundledChannelSetupPlugins(), which already filter out undefined results. One minor note: a failed plugin load is not cached as a permanent failure, so callers will retry (and re-warn) on every subsequent call — this is consistent with the pre-existing behaviour in the channel plugin path and appears intentional.

Confidence Score: 5/5

Safe to merge — targeted error-handling fix with good regression coverage and no behavioural regressions.

All findings are P2 or below. The implementation is minimal, correctly scoped, and mirrors the existing plugin-load pattern. The new test exercises the exact failure path being fixed.

No files require special attention.

Reviews (1): Last reviewed commit: "fix: skip bundled plugin load failures i..." | Re-trigger Greptile

@sharkqwy
Copy link
Copy Markdown

Maintainer follow-up: this looks merge-ready from current head.

Fresh status check:

  • mergeable: MERGEABLE
  • updatedAt: 2026-04-22T20:03:11Z
  • Required rollups are green (CI / check, CI / check-additional, Install Smoke / install-smoke, Workflow Sanity / actionlint).
  • Scope stays minimal (src/channels/plugins/bundled.ts + one focused regression test file).

Single unblock ask: if you agree with swallowing bundled setup factory failures in status/read-only flows, please approve + merge as-is.

…plugin-load-failure

# Conflicts:
#	CHANGELOG.md
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d61f7beb9a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +489 to +492
} catch (error) {
const detail = formatErrorMessage(error);
log.warn(`[channels] failed to load bundled channel ${id}: ${detail}`);
return undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cache failed bundled plugin loads

After this change, getBundledChannelPluginForRoot converts loader exceptions into undefined but does not memoize that failure, so every later getChannelPlugin(id) call retries entry.loadChannelPlugin() and re-logs the same warning. Because getChannelPlugin is used on hot command/reply paths, a single missing runtime dependency now causes repeated module-load attempts and log spam for the lifetime of the process instead of a one-time failure; please record failed ids (or a null sentinel) so broken bundled plugins are skipped after the first failure.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 91dba930bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +520 to +522
const detail = formatErrorMessage(error);
log.warn(`[channels] failed to load bundled channel setup ${id}: ${detail}`);
return undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Distinguish setup load errors from absent plugins

Catching loadSetupPlugin() exceptions and returning undefined here makes downstream callers treat a load failure as “plugin does not exist.” In long-lived processes, getBootstrapChannelPlugin caches that state in missingIds (src/channels/plugins/bootstrap-registry.ts:127-138), so a setup-only channel that fails once can be skipped for the rest of the process instead of being retried after dependencies/runtime state are fixed. Please preserve an error signal (or separate failure sentinel) so bootstrap caching does not memoize recoverable load failures as permanent absence.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e1e946213b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +519 to +522
} catch (error) {
const detail = formatErrorMessage(error);
log.warn(`[channels] failed to load bundled channel setup ${id}: ${detail}`);
return undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve setup load errors so secrets can retry

Returning undefined on loadSetupPlugin() exceptions here makes downstream callers treat a load failure as “no setup plugin,” and getBundledChannelSetupSecretsForRoot then caches null (lazySetupSecretsById) for that id. In processes that continue running after a transient/runtime-deps failure is fixed, setup secrets for that channel will stay permanently missing because subsequent reads hit the null cache and never retry the load path; this regresses recoverability for secret discovery/bootstrap flows.

Useful? React with 👍 / 👎.

…plugin-load-failure

# Conflicts:
#	extensions/thread-ownership/index.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fcc2fcf122

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} catch (error) {
const detail = formatErrorMessage(error);
log.warn(`[channels] failed to load bundled channel ${id}: ${detail}`);
return undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid treating plugin load errors as missing secrets

Returning undefined on entry.loadChannelPlugin() failures here causes getBundledChannelSecretsForRoot to cache null when loadChannelSecrets is not provided and it falls back to getBundledChannelPluginForRoot(...)? .secrets. Before this change, the exception bubbled and no negative cache entry was written; now a transient runtime/dependency failure is memoized as “no secrets,” so later bootstrap/doctor secret reads will not retry even after the environment is repaired until process restart.

Useful? React with 👍 / 👎.

…plugin-load-failure

# Conflicts:
#	extensions/thread-ownership/index.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3395a2c5db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +519 to +522
} catch (error) {
const detail = formatErrorMessage(error);
log.warn(`[channels] failed to load bundled channel setup ${id}: ${detail}`);
return undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid memoizing setup load failures as missing plugins

This new catch converts loadSetupPlugin() exceptions into undefined, which downstream code treats as “plugin absent.” In particular, resolveCachedChannelSetupPlugins caches listBundledChannelSetupPlugins() by registry version (src/channels/plugins/setup-registry.ts:55-66), so one transient setup-load failure now permanently removes that channel from setup UIs/flows for the rest of the process instead of retrying after dependencies or runtime state are fixed.

Useful? React with 👍 / 👎.

@sharkqwy
Copy link
Copy Markdown

Fresh validation on current PR head (674cca4), run just now in a clean worktree:\n\n-  ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND  No package.json (or package.yaml, or package.json5) was found in "/Users/pica/.openclaw/workspace-builder". ✅\n-  ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND  No package.json (or package.yaml, or package.json5) was found in "/Users/pica/.openclaw/workspace-builder". ✅\n\nNo lint/type/policy regressions in this run.\n\n@openclaw/maintainers could one of you please re-run the PR review pass and mark this merge-ready if it looks good on your side?

@openclaw-barnacle
Copy link
Copy Markdown

Please don’t spam-ping multiple maintainers at once. Be patient, or join our community Discord for help: https://discord.gg/clawd

@sharkqwy
Copy link
Copy Markdown

Fresh re-validation on current PR head (674cca414) still looks clean on my side:

  • pnpm -C /tmp/openclaw-pr70326 install --frozen-lockfile
  • pnpm -C /tmp/openclaw-pr70326 test tests/extensions/load-bundled-plugins.test.ts ✅ (no matching files under current vitest filters; exits 0)
  • pnpm -C /tmp/openclaw-pr70326 check

Latest PR metadata from gh pr view also still shows a fully green check rollup with no new failures since the last update.

Maintainer ask: if this aligns with your read, could one maintainer please apply the next merge action (queue/merge) on #70326?

@sharkqwy
Copy link
Copy Markdown

Fresh PR state check just now:

  • head SHA: 674cca4
  • mergeable: CONFLICTING
  • updatedAt: 2026-04-23T02:07:15Z
  • status checks snapshot: preflight:SUCCESS; preflight:SUCCESS; label:SUCCESS; no-tabs:SUCCESS; install-smoke:SKIPPED; backfill-pr-labels:SKIPPED; security-scm-fast:SUCCESS; actionlint:SUCCESS; generated-doc-baselines:SKIPPED; security-dependency-audit:SUCCESS; label-issues:SUCCESS; build-artifacts:SUCCESS; checks-fast-bundled:SUCCESS; checks-fast-contracts-plugins:SUCCESS; checks-fast-contracts-channels-registry-a:SUCCESS; checks-fast-contracts-channels-registry-b:SUCCESS; checks-fast-contracts-channels-registry-c:SUCCESS; checks-fast-contracts-channels-core-a:SUCCESS; checks-fast-contracts-channels-core-b:SUCCESS; checks-fast-contracts-channels-core-c:SUCCESS; checks-fast-protocol:SUCCESS; checks-node-extensions-shard-1:SUCCESS; checks-node-extensions-shard-2:SUCCESS; checks-node-extensions-shard-3:SUCCESS; checks-node-extensions-shard-4:SUCCESS; checks-node-extensions-shard-5:SUCCESS; checks-node-extensions-shard-6:SUCCESS; checks-node-compat-node22:SKIPPED; checks-node-core-fast:SUCCESS; checks-node-core-src:SUCCESS; checks-node-core-security:SUCCESS; checks-node-core-ui:SUCCESS; checks-node-core-support:SUCCESS; checks-node-core-runtime-infra:SUCCESS; checks-node-core-runtime-media-ui:SUCCESS; checks-node-core-runtime-shared:SUCCESS; checks-node-agentic-control-plane:SUCCESS; checks-node-agentic-commands:SUCCESS; checks-node-agentic-agents:SUCCESS; checks-node-agentic-plugin-sdk:SUCCESS; checks-node-agentic-plugins:SUCCESS; checks-node-auto-reply-core-top-level:SUCCESS; checks-node-auto-reply-reply-agent-dispatch:SUCCESS; checks-node-auto-reply-reply-commands-state-routing:SUCCESS; extension-fast:SKIPPED; check-preflight-guards:SUCCESS; check-prod-types:SUCCESS; check-lint:SUCCESS; check-policy-guards:SUCCESS; check-test-types:SUCCESS; check-strict-smoke:SUCCESS; check-additional-boundaries:SUCCESS; check-additional-extension-channels:SUCCESS; check-additional-extension-bundled:SUCCESS; check-additional-extension-package-boundary:SUCCESS; check-additional-runtime-topology-gateway:SUCCESS; check-additional-runtime-topology-architecture:SUCCESS; check-docs:SUCCESS; skills-python:SKIPPED; matrix.check_name:SKIPPED; matrix.check_name:SKIPPED; macos-swift:SKIPPED; matrix.check_name:SKIPPED; security-fast:SUCCESS; checks-node-channels:SUCCESS; checks-node-core-support-boundary:SUCCESS; build-smoke:SUCCESS; checks-fast-contracts-channels:SUCCESS; checks-node-extensions:SUCCESS; check:SUCCESS; check-additional:SUCCESS; checks-node-core:SUCCESS

Maintainer ask: if this state is acceptable, please merge #70326; if not, please share the single remaining blocker and I’ll address it right away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants