Skip to content

[Bug]: file:// plugin dedup silently drops plugins when multiple share the same filename (e.g. index.js) #14304

@Aegis-commits

Description

@Aegis-commits

Description

When two or more plugins are loaded via file:// paths and their JS filenames are identical (e.g. both named index.js), deduplicatePlugins() silently drops all but one. No error or warning is logged.

Reproduction

// opencode.json
{
  "plugin": [
    "file:///home/user/plugin-a/dist/index.js",
    "file:///home/user/plugin-b/dist/index.js"
  ]
}

Expected: Both plugins load.
Actual: Only one loads (the later entry wins). The other is silently discarded.

Root Cause

getPluginName() extracts just the bare filename (without extension) for file:// URLs. Both paths resolve to canonical name "index". deduplicatePlugins() then treats them as the same plugin and keeps only the last one (reverse-order processing, last = highest priority).

Impact

This is a silent failure — no error, no warning, no log entry. The dropped plugin simply doesn't exist at runtime. This is especially likely during local plugin development where dist/index.js is the standard build output for most bundlers (bun, esbuild, rollup, etc.).

Suggested Fix

For file:// URLs, derive the canonical name from a more unique portion of the path rather than just the bare filename. Options:

  1. Use the parent directory name + filename (e.g. plugin-a/index"plugin-a")
  2. Use the full path as the canonical name for file:// entries
  3. At minimum, log a warning when dedup discards a file:// plugin

Workaround

Ensure each file:// plugin has a unique JS filename:

ln -sf /path/to/plugin/dist/index.js /path/to/plugin/dist/my-plugin.js
{
  "plugin": [
    "file:///home/user/plugin-a/dist/plugin-a.js",
    "file:///home/user/plugin-b/dist/index.js"
  ]
}

Environment

  • OpenCode (latest)
  • Linux x86_64
  • Multiple file:// plugins in config

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions