stablyai/orca · error
packaged plugin contains a symlink: ${relative(root, entryPa
Error message
packaged plugin contains a symlink: ${relative(root, entryPath)} What it means
Thrown by the packaged plugin resource verifier when lstatSync detects a symbolicic link during the recursive tree walk. Packaged plugins must contain only real files and directories — symlinks break content-addressable hashing (they produce platform-dependent behavior), cause issues on Windows where symlinks may not be supported, and can escape the plugin root. The check uses lstatSync (not statSync) specifically to detect the link itself rather than its target.
Source
Thrown at config/scripts/verify-packaged-plugin-resources.cjs:33
const files = []
let entriesVisited = 0
let totalBytes = 0
const visit = (directory) => {
const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) =>
left.name < right.name ? -1 : left.name > right.name ? 1 : 0
)
for (const entry of entries) {
if (directory === root && entry.name === '.git') {
continue
}
const entryPath = join(directory, entry.name)
const metadata = lstatSync(entryPath)
entriesVisited += 1
if (entriesVisited > MAX_PLUGIN_FILES) {
throw new Error(`plugin exceeds the ${MAX_PLUGIN_FILES}-entry limit`)
}
if (metadata.isSymbolicLink()) {
throw new Error(`packaged plugin contains a symlink: ${relative(root, entryPath)}`)
}
if (metadata.isDirectory()) {
visit(entryPath)
} else if (metadata.isFile()) {
totalBytes += metadata.size
if (totalBytes > MAX_PLUGIN_TOTAL_BYTES) {
throw new Error(`plugin exceeds the ${MAX_PLUGIN_TOTAL_BYTES}-byte limit`)
}
files.push({ path: entryPath, size: metadata.size })
} else {
throw new Error(`packaged plugin contains an unsupported entry: ${entryPath}`)
}
}
}
visit(root)
const hash = createHash('sha256').update('orca-plugin-tree-v1\0')
for (const file of files) {
const relativePath = relative(root, file.path).replaceAll('\\', '/')View on GitHub (pinned to 1136503c6a)
Solutions
- Identify the symlink from the error message (it includes the relative path): ls -la <pluginRoot>/<relativePath>.
- Replace the symlink with a real copy of the target file or directory.
- Ensure the packaging step resolves all symlinks before creating the plugin archive: cp -rL or rsync -L.
- If using pnpm, run the packaging step after pnpm install --shamefully-hoist or use a bundler that produces a self-contained output.
Defensive patterns
Strategy: validation
Validate before calling
// Before packaging, scan for symlinks in the plugin directory.
const { execSync } = require('node:child_process')
function preCheckPluginSymlinks(pluginRoot) {
try {
const output = execSync(`find ${JSON.stringify(pluginRoot)} -type l`, {
encoding: 'utf8'
}).trim()
return { ok: output.length === 0, symlinks: output.split('\n').filter(Boolean) }
} catch {
return { ok: true, symlinks: [] }
}
} Prevention
- Resolve all symlinks during the packaging copy step: use cp -rL or rsync -L instead of plain cp -r.
- If using pnpm, verify the packaged output doesn't contain the symlink-based node_modules layout; use --shamefully-hoist or a bundler.
- Add a pre-packaging symlink scan to the CI pipeline that fails on any symlink found.
When it happens
Trigger: hashPackagedPluginTree(root) encounters an entry where metadata.isSymbolicLink() returns true. Common in pnpm/yarn-workspace monorepos where node_modules use symlinks for package linking, or when a developer creates convenience symlinks within a plugin directory that get packaged.
Common situations: The plugin was developed in a pnpm workspace where dependencies are symlinked; a developer created a symlink for convenience (e.g., linking to a shared config); the packaging step dereferences most symlinks but missed some; cross-platform builds where symlinks created on Linux are packaged into a Windows-incompatible layout.
Related errors
- plugin exceeds the ${MAX_PLUGIN_FILES}-entry limit
- plugin exceeds the ${MAX_PLUGIN_TOTAL_BYTES}-byte limit
- packaged plugin contains an unsupported entry: ${entryPath}
- [verify-packaged-plugin-resources] invalid ${label} at ${pat
- [verify-packaged-plugin-resources] missing launch directory
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/fb830c99a8ae60e7.
Report an issue: GitHub.