{"record":{"id":"9a9acd9d57b87110","repo":"stablyai/orca","slug":"verify-packaged-plugin-resources-bundled-plugin-9a9acd","errorCode":null,"errorMessage":"[verify-packaged-plugin-resources] bundled plugin entry is invalid","messagePattern":"\\[verify-packaged-plugin-resources\\] bundled plugin entry is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/scripts/verify-packaged-plugin-resources.cjs","lineNumber":87,"sourceCode":"\nfunction verifyPackagedPluginResources(resourcesDir) {\n  const launchRoot = join(resourcesDir, 'plugins', 'launch')\n  if (!statSync(launchRoot).isDirectory()) {\n    throw new Error(`[verify-packaged-plugin-resources] missing launch directory at ${launchRoot}`)\n  }\n  const index = readJsonFile(join(launchRoot, 'bundled-plugins.json'), 'bundled plugin index')\n  readJsonFile(join(launchRoot, 'orca-marketplace.json'), 'marketplace index')\n  if (index?.version !== 1 || !Array.isArray(index.plugins) || index.plugins.length === 0) {\n    throw new Error('[verify-packaged-plugin-resources] bundled plugin index is empty or invalid')\n  }\n  const resolvedRoot = resolve(launchRoot)\n  for (const entry of index.plugins) {\n    if (\n      typeof entry?.pluginKey !== 'string' ||\n      typeof entry.path !== 'string' ||\n      !/^[0-9a-f]{64}$/.test(entry.contentHash)\n    ) {\n      throw new Error('[verify-packaged-plugin-resources] bundled plugin entry is invalid')\n    }\n    const pluginRoot = resolve(launchRoot, entry.path)\n    const fromRoot = relative(resolvedRoot, pluginRoot)\n    if (!fromRoot || fromRoot === '..' || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {\n      throw new Error('[verify-packaged-plugin-resources] bundled plugin path escapes launch root')\n    }\n    const manifest = readJsonFile(join(pluginRoot, 'orca-plugin.json'), 'plugin manifest')\n    if (`${manifest.publisher}.${manifest.id}` !== entry.pluginKey) {\n      throw new Error(\n        `[verify-packaged-plugin-resources] manifest identity does not match ${entry.pluginKey}`\n      )\n    }\n    if (hashPackagedPluginTree(pluginRoot) !== entry.contentHash) {\n      throw new Error(\n        `[verify-packaged-plugin-resources] packaged bytes do not match ${entry.pluginKey}`\n      )\n    }\n  }","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/verify-packaged-plugin-resources.cjs#L69-L105","documentation":"Thrown by the packaged plugin resource verifier when any entry in the bundled-plugins.json plugins array fails field-level validation. Each entry must have: pluginKey as a string, path as a string, and contentHash matching the regex /^[0-9a-f]{64}$/ (a 64-character lowercase hex SHA-256 hash). If any of these checks fail, the entry is considered invalid.","triggerScenarios":"An entry in bundled-plugins.json has a missing or non-string pluginKey (e.g., null, number); path is missing or not a string; contentHash is missing, not a string, uppercase, truncated, or not a valid hex SHA-256 hash (e.g., contains non-hex characters or is the wrong length).","commonSituations":"The indexing script was modified and stopped generating one of the required fields; a hash was computed with a different algorithm (e.g., MD5 producing 32 chars instead of SHA-256's 64); the hash was uppercased by a JSON serializer or post-processor; a manual edit to bundled-plugins.json corrupted an entry.","solutions":["Inspect each entry in bundled-plugins.json and check for missing/null fields: ensure pluginKey and path are strings and contentHash is a 64-char lowercase hex string.","If the hash is the wrong length or format, verify the indexing script uses createHash('sha256').digest('hex') (lowercase hex, 64 chars).","Re-run the plugin indexing step to regenerate the index with correct field values.","If the schema was intentionally changed, update the validation in verify-packaged-plugin-resources.cjs:82-86 to match."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Validate a single bundled plugin entry shape.\nfunction isValidPluginEntry(entry) {\n  return (\n    typeof entry === 'object' &&\n    entry !== null &&\n    typeof entry.pluginKey === 'string' &&\n    typeof entry.path === 'string' &&\n    typeof entry.contentHash === 'string' &&\n    /^[0-9a-f]{64}$/.test(entry.contentHash)\n  )\n}","tryCatchPattern":null,"preventionTips":["Ensure the indexing script always computes contentHash using createHash('sha256').digest('hex') to guarantee lowercase 64-char hex.","Add unit tests for the indexing script that verify every entry it produces passes the validation regex.","Never manually edit entries in bundled-plugins.json; always regenerate from the indexing pipeline."],"tags":["plugin-packaging","ci-gate","resource-verification","schema-validation","content-hash"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}