#21871: fix(plugins): suppress false duplicate warning when user-installed plugin shadows bundled
docs
size: S
Cluster:
Plugin Management Enhancements
## Summary
When a user installs a plugin (e.g. `nextcloud-talk`) via `openclaw plugins nextcloud-talk install`, the registry emitted a spurious `duplicate plugin id detected` warning. The plugin was working correctly — the user-installed copy was winning over the bundled copy as expected — but the warning was alarming and logged on every startup.
## Root Cause
The duplicate-detection branch in `loadPluginManifestRegistry` handled two cases:
1. **Same physical path** (via symlinks/aliases) → silent skip ✅
2. **Different paths** → always warn ❌
Case 2 incorrectly treated "user-installed plugin shadows bundled copy" the same as a genuine conflict between two non-bundled plugins. The former is expected behavior; only the latter deserves a warning.
## Fix
Extend the silent-preference path to also cover the case where exactly one of the two candidates has `bundled` origin (XOR). The higher-precedence copy (`config > workspace > global > bundled`) wins silently without a warning.
A warning still fires when:
- Two **non-bundled** plugins claim the same ID (genuine conflict)
- Two **bundled** plugins at different paths share an ID (shouldn't happen in practice)
```typescript
// Before: only samePlugin was silent
if (samePlugin) { ... }
diagnostics.push({ level: "warn", ... }); // ← fired for user-install vs bundled
// After: samePlugin OR exactly one bundled → silent
const existingIsBundled = existing.candidate.origin === "bundled";
const candidateIsBundled = candidate.origin === "bundled";
const oneBundled = existingIsBundled !== candidateIsBundled;
if (samePlugin || oneBundled) { ... }
diagnostics.push({ level: "warn", ... }); // ← only fires for genuine conflicts
```
## Tests
Updated + added 4 test cases in `manifest-registry.test.ts`:
| Scenario | Result |
|---|---|
| `global` + `workspace` same ID (non-bundled conflict) | ✅ warning fires |
| `global` shadows `bundled` same ID | ✅ no warning, global wins |
| `config` shadows `bundled` same ID | ✅ no warning, config wins |
| two `bundled` at different paths same ID | ✅ warning fires |
| existing symlink / same-path tests | ✅ unchanged, still pass |
All 7 tests pass.
Fixes #21714
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed spurious duplicate plugin warning when user-installed plugins shadow bundled versions. The change introduces XOR logic to detect when exactly one plugin is bundled, allowing the higher-precedence user-installed copy to silently win. Warnings now only fire for genuine conflicts between non-bundled plugins or between multiple bundled plugins at different paths.
- Modified duplicate detection in `loadPluginManifestRegistry` to distinguish between expected shadowing (user vs bundled) and genuine conflicts
- Added four comprehensive test cases covering non-bundled conflicts, user-shadowing-bundled scenarios, and bundled-bundled conflicts
- Updated existing test to use non-bundled origins (global vs workspace) since bundled vs global no longer warns
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with no risk
- The implementation is straightforward, well-tested, and addresses a specific false-positive warning. The XOR logic correctly distinguishes between expected shadowing (user-installed vs bundled) and genuine conflicts. All edge cases are covered by comprehensive tests, and the change is minimal and focused.
- No files require special attention
<sub>Last reviewed commit: c38c2f2</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#20499: test(plugins): add bundled+config duplicate discovery regression
by dcol91863 · 2026-02-19
83.2%
#20889: fix: suppress duplicate warning for virtual auto-enabled entries
by akramcodez · 2026-02-19
81.2%
#12084: fix: prevent false duplicate plugin warning for bundled channel plu...
by shadril238 · 2026-02-08
80.8%
#20424: Fix plugin extension path traversal in discovery/install
by markmusson · 2026-02-18
78.7%
#18730: fix(plugins): suppress duplicate ID warnings for intentional origin...
by cedillarack · 2026-02-17
78.5%
#21660: fix(plugins): require explicit allowlist for non-bundled plugins
by AI-Reviewer-QS · 2026-02-20
77.8%
#2556: fix(plugin-install): handle existing plugins and filter workspace deps
by longmaba · 2026-01-27
77.3%
#7090: fix: plugin install uses manifest ID for folder name (#2796)
by dial481 · 2026-02-02
76.6%
#18966: fix(config): downgrade unknown bundled plugin references to warnings
by moxunjinmu · 2026-02-17
76.6%
#15618: fix(plugins): reject async plugin registration instead of silently ...
by AI-Reviewer-QS · 2026-02-13
76.3%