{"record":{"id":"87392f7be7f0fb16","repo":"stablyai/orca","slug":"unsupported-historical-tree-entry-entry","errorCode":null,"errorMessage":"Unsupported historical tree entry: ${entry}","messagePattern":"Unsupported historical tree entry: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/scripts/verify-skill-update-roundtrip.mjs","lineNumber":88,"sourceCode":"      return { tag: `v${release.appVersion}`, snapshot }\n    }\n  }\n  throw new Error(`No historical released snapshot is available for ${name}`)\n}\n\nasync function materializePackage(name, tag, destination) {\n  const prefix = `skills/${name}/`\n  const entries = execFileSync('git', ['ls-tree', '-r', '-z', tag, '--', `skills/${name}`])\n    .toString('utf8')\n    .split('\\0')\n    .filter(Boolean)\n  if (entries.length === 0) {\n    throw new Error(`${tag} does not contain ${name}`)\n  }\n  for (const entry of entries) {\n    const match = /^(\\d+) (\\w+) ([a-f0-9]+)\\t(.+)$/.exec(entry)\n    if (!match || match[2] !== 'blob') {\n      throw new Error(`Unsupported historical tree entry: ${entry}`)\n    }\n    const relativePath = match[4].slice(prefix.length)\n    const destinationPath = path.join(destination, ...relativePath.split('/'))\n    await mkdir(path.dirname(destinationPath), { recursive: true })\n    await writeFile(destinationPath, execFileSync('git', ['cat-file', 'blob', match[3]]))\n    if (process.platform !== 'win32' && match[1] === '100755') {\n      await chmod(destinationPath, 0o755)\n    }\n  }\n}\n\nasync function seedPlacement(name, tag) {\n  const canonical = path.join(home, '.agents', 'skills', name)\n  await materializePackage(name, tag, canonical)\n  const providerRoot = path.join(home, '.claude', 'skills')\n  const provider = path.join(providerRoot, name)\n  await mkdir(providerRoot, { recursive: true })\n  await (shape === 'copy'","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/verify-skill-update-roundtrip.mjs#L70-L106","documentation":"materializePackage() parses each 'git ls-tree -r' entry with the regex /^(\\d+) (\\w+) ([a-f0-9]+)\\t(.+)$/ and requires match[2] to be 'blob'. It throws on any entry that isn't a blob — submodules (commit), trees, or any malformed line — because the materializer only knows how to cat-file a blob.","triggerScenarios":"The skill tree at that tag contains a git submodule pointer (mode 160000, type commit); a nested directory entry leaks through (shouldn't with -r but could with tree objects); ls-tree output format change across git versions; the entry line contains characters that break the strict regex.","commonSituations":"Skill historically vendored a submodule; unusual file mode bits in the tree; git version producing a format the regex doesn't anticipate; corruption in the tree object.","solutions":["Run 'git ls-tree -r <tag> -- skills/<name>' and look for any line whose type column is not 'blob' (e.g. commit entries = submodules).","If a submodule is present historically, extend materializePackage to handle 'commit' entries or skip them deliberately.","Confirm the git version used produces the standard ls-tree format (the AGENTS.md git-compat baseline is 2.25).","Regenerate the snapshot from a tag whose tree contains only blobs."],"exampleFix":"// before\nif (!match || match[2] !== 'blob') {\n  throw new Error(`Unsupported historical tree entry: ${entry}`)\n}\n// after — tolerate and skip submodule (commit) entries\nif (!match) throw new Error(`Unsupported historical tree entry: ${entry}`)\nif (match[2] === 'commit') continue // submodule pointer; nothing to materialize\nif (match[2] !== 'blob') throw new Error(`Unsupported historical tree entry: ${entry}`)","handlingStrategy":"validation","validationCode":"// Reject trees containing non-blob entries up front so the failure is clearer:\nfunction assertTreeIsBlobsOnly(name, tag) {\n  const entries = execFileSync('git', ['ls-tree', '-r', tag, '--', `skills/${name}`], { encoding: 'utf8' }).trim().split('\\n').filter(Boolean)\n  for (const e of entries) {\n    const type = /^\\d+ (\\w+) /.exec(e)?.[1]\n    if (type && type !== 'blob') {\n      throw new Error(`Refusing to materialize: ${tag} skills/${name} contains ${type} entry: ${e}`)\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't vendor submodules inside skill packages; if unavoidable, extend materializePackage to skip 'commit' entries deliberately.","Run the script on a git baseline (>=2.25) whose ls-tree format matches the regex.","If you see this, inspect the offending entry to decide skip-vs-fix rather than weakening the regex blindly."],"tags":["git","skill-update","submodule","parsing","test-fixture"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}