{"record":{"id":"fb365ff32d32ee4b","repo":"stablyai/orca","slug":"plugin-exceeds-the-max-plugin-files-entry-limit","errorCode":null,"errorMessage":"plugin exceeds the ${MAX_PLUGIN_FILES}-entry limit","messagePattern":"plugin exceeds the (.+?)-entry limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/scripts/verify-packaged-plugin-resources.cjs","lineNumber":30,"sourceCode":"}\n\nfunction hashPackagedPluginTree(root) {\n  const files = []\n  let entriesVisited = 0\n  let totalBytes = 0\n  const visit = (directory) => {\n    const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) =>\n      left.name < right.name ? -1 : left.name > right.name ? 1 : 0\n    )\n    for (const entry of entries) {\n      if (directory === root && entry.name === '.git') {\n        continue\n      }\n      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)","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/verify-packaged-plugin-resources.cjs#L12-L48","documentation":"Thrown by the packaged plugin resource verifier when the recursive file count of a single plugin tree exceeds MAX_PLUGIN_FILES (2000). The counter increments for every directory entry visited (files, subdirectories, symlinks) and throws immediately when entriesVisited exceeds the limit. This is a size guardrail: a plugin with more than 2000 entries is likely packaging node_modules, build artifacts, or other unintended content.","triggerScenarios":"hashPackagedPluginTree(root) is called for a bundled plugin whose directory tree contains more than 2000 filesystem entries. This typically happens when a .gitignore or packaging exclusion is missing and node_modules, dist folders, test fixtures, or .git history are included in the packaged plugin.","commonSituations":"A plugin's packaging step forgot to exclude node_modules; a build artifact directory (dist/, build/) with many chunk files was included; a plugin bundles test fixtures or large datasets; symlinks from a development setup (pnpm, yarn workspaces) were dereferenced into many real files during packaging.","solutions":["Inspect the plugin directory tree: find <pluginRoot> -type f | wc -l to see the actual file count.","Ensure the plugin packaging step excludes node_modules, dist, .git, and test directories.","If the plugin legitimately needs many files, evaluate whether some can be bundled into a single file (e.g., pack data files into a tar/zip or inline them).","If 2000 is genuinely too low for a valid plugin, raise MAX_PLUGIN_FILES in config/scripts/verify-packaged-plugin-resources.cjs:5 — but first confirm the extra files are intentional."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before packaging, count files in the plugin directory.\nconst { execSync } = require('node:child_process')\n\nfunction preCheckPluginFileCount(pluginRoot, maxFiles = 2000) {\n  const output = execSync(`find ${JSON.stringify(pluginRoot)} -type f | wc -l`, {\n    encoding: 'utf8'\n  })\n  const count = parseInt(output.trim(), 10)\n  return { ok: count <= maxFiles, count, maxFiles }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Configure the plugin packaging step to exclude node_modules, dist, .git, and test directories using an explicit allowlist or denylist.","Add a pre-packaging check in the plugin build pipeline that counts files and warns if approaching the 2000 limit.","Regularly audit plugin contents for accidental inclusion of build artifacts or dependency trees."],"tags":["plugin-packaging","file-limit","ci-gate","resource-verification"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}