{"record":{"id":"586f880a22eaeb22","repo":"stablyai/orca","slug":"packaged-plugin-contains-an-unsupported-entry-e","errorCode":null,"errorMessage":"packaged plugin contains an unsupported entry: ${entryPath}","messagePattern":"packaged plugin contains an unsupported entry: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/scripts/verify-packaged-plugin-resources.cjs","lineNumber":44,"sourceCode":"      const entryPath = join(directory, entry.name)\n      const metadata = lstatSync(entryPath)\n      entriesVisited += 1\n      if (entriesVisited > MAX_PLUGIN_FILES) {\n        throw new Error(`plugin exceeds the ${MAX_PLUGIN_FILES}-entry limit`)\n      }\n      if (metadata.isSymbolicLink()) {\n        throw new Error(`packaged plugin contains a symlink: ${relative(root, entryPath)}`)\n      }\n      if (metadata.isDirectory()) {\n        visit(entryPath)\n      } else if (metadata.isFile()) {\n        totalBytes += metadata.size\n        if (totalBytes > MAX_PLUGIN_TOTAL_BYTES) {\n          throw new Error(`plugin exceeds the ${MAX_PLUGIN_TOTAL_BYTES}-byte limit`)\n        }\n        files.push({ path: entryPath, size: metadata.size })\n      } else {\n        throw new Error(`packaged plugin contains an unsupported entry: ${entryPath}`)\n      }\n    }\n  }\n  visit(root)\n  const hash = createHash('sha256').update('orca-plugin-tree-v1\\0')\n  for (const file of files) {\n    const relativePath = relative(root, file.path).replaceAll('\\\\', '/')\n    hashLength(hash, Buffer.byteLength(relativePath, 'utf8'))\n    hash.update(relativePath, 'utf8')\n    hashLength(hash, file.size)\n    hash.update(readFileSync(file.path))\n  }\n  return hash.digest('hex')\n}\n\nfunction readJsonFile(path, label) {\n  try {\n    return JSON.parse(readFileSync(path, 'utf8'))","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/verify-packaged-plugin-resources.cjs#L26-L62","documentation":"Thrown by the packaged plugin resource verifier when an entry in the plugin tree is neither a regular file, a directory, nor a symbolic link. lstatSync returned metadata that fails all three checks (isSymbolicLink, isDirectory, isFile), indicating an exotic filesystem entry type such as a socket, FIFO (named pipe), character/block device, or other special file. These entry types are not meaningful in a packaged plugin and break content hashing (readFileSync would fail or block on them).","triggerScenarios":"hashPackagedPluginTree(root) encounters a special file during the recursive walk. This can happen when a development artifact (e.g., a Unix socket created by a dev server, a FIFO used for IPC) was inadvertently included in the packaged plugin tree.","commonSituations":"A hot-reload dev server or IPC mechanism left a socket file in the plugin directory; a build tool created a named pipe for streaming; packaging from a directory that contains OS-level device files (e.g., packaging from /dev or /tmp without cleanup); a broken packaging pipeline that copied special files.","solutions":["Identify the unsupported entry from the error message (it includes the full path): file <entryPath> to determine its type.","Remove the special file from the plugin source tree.","Ensure the packaging step only copies regular files and directories: use rsync or tar with appropriate exclude filters.","Add a .gitignore or packaging exclusion for any path that generates special files during development."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before packaging, scan for special (non-regular, non-directory) files.\nconst { execSync } = require('node:child_process')\n\nfunction preCheckSpecialFiles(pluginRoot) {\n  // Find files that are NOT regular files or directories (sockets, FIFOs, devices)\n  try {\n    const output = execSync(\n      `find ${JSON.stringify(pluginRoot)} -type s -o -type p -o -type b -o -type c`,\n      { encoding: 'utf8' }\n    ).trim()\n    return { ok: output.length === 0, specialFiles: output.split('\\n').filter(Boolean) }\n  } catch {\n    return { ok: true, specialFiles: [] }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clean the plugin directory before packaging: remove dev server sockets, IPC pipes, and other ephemeral files.","Use an explicit allowlist of files/directories to package rather than copying the entire source tree.","Run the packaging step in a clean CI environment where dev servers have not created artifacts."],"tags":["plugin-packaging","filesystem","ci-gate","resource-verification","special-files"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}