{"record":{"id":"11087ab9a21c2c15","repo":"paperclipai/paperclip","slug":"unsupported-manifest-shape","errorCode":null,"errorMessage":"unsupported manifest shape","messagePattern":"unsupported manifest shape","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/install-store.ts","lineNumber":224,"sourceCode":"  source: InstallSource,\n  identifier: string,\n): string {\n  if (!/^[A-Za-z0-9._-]+$/.test(identifier)) {\n    throw new Error(`Invalid install payload identifier '${identifier}'.`);\n  }\n  return path.join(paths.installsRoot, source, identifier);\n}\n\nexport function readInstallManifest(paths = resolveInstallStorePaths()): InstallManifest | null {\n  try {\n    const value = JSON.parse(fs.readFileSync(paths.manifestPath, \"utf8\")) as InstallManifest;\n    if (\n      value.schemaVersion !== INSTALL_MANIFEST_VERSION ||\n      (value.source !== \"npm\" && value.source !== \"git\") ||\n      !Array.isArray(value.previous) ||\n      typeof value.payloadPath !== \"string\"\n    ) {\n      throw new Error(\"unsupported manifest shape\");\n    }\n    return value;\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n    throw new Error(`Could not read managed install manifest at ${paths.manifestPath}: ${String(error)}`);\n  }\n}\n\nexport function writeInstallManifestAtomic(\n  manifest: InstallManifest,\n  paths = resolveInstallStorePaths(),\n): void {\n  ensurePrivateDirectory(paths.cliRoot);\n  const temporaryPath = `${paths.manifestPath}.tmp-${process.pid}-${Date.now()}`;\n  try {\n    fs.writeFileSync(temporaryPath, `${JSON.stringify(manifest, null, 2)}\\n`, { mode: 0o600 });\n    fs.renameSync(temporaryPath, paths.manifestPath);\n  } finally {","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/install-store.ts#L206-L242","documentation":"Thrown internally by readInstallManifest() when the manifest JSON parses successfully but fails a structural shape check: schemaVersion must equal INSTALL_MANIFEST_VERSION (1), source must be 'npm' or 'git', previous must be an array, and payloadPath must be a string. If any of these fail, the inner throw produces this bare message. Note: this error is caught and re-wrapped by the outer catch into error 277's message, so callers normally see 277, not this raw text.","triggerScenarios":"Called readInstallManifest() where install.json exists, parses as JSON, but has a wrong/missing schemaVersion, a source value other than 'npm'/'git', a non-array previous field, or a non-string payloadPath.","commonSituations":"1) A future Paperclip version bumps INSTALL_MANIFEST_VERSION and an older CLI reads the newer manifest. 2) install.json was hand-edited or partially overwritten. 3) A different tool wrote a file at the manifest path. 4) A migration step failed to update schemaVersion.","solutions":["Inspect ~/.paperclip/cli/install.json and confirm schemaVersion, source, previous (array), and payloadPath (string) match the expected shape.","If the manifest is from an incompatible newer version, upgrade the CLI to match, or remove the store and reinstall.","If corrupt, remove cliRoot and reinitialize with 'paperclipai install'.","Restore install.json from a backup if one exists."],"exampleFix":"// before: install.json has \"schemaVersion\": 2 with CLI expecting 1\n$ rm -rf ~/.paperclip/cli\n$ paperclipai install   # writes manifest with schemaVersion 1","handlingStrategy":"validation","validationCode":"import fs from \"node:fs\";\nimport { INSTALL_MANIFEST_VERSION, resolveInstallStorePaths } from \"./install-store.js\";\n\nfunction manifestShapeIsValid(paths = resolveInstallStorePaths()): boolean {\n  try {\n    const v = JSON.parse(fs.readFileSync(paths.manifestPath, \"utf8\"));\n    return v.schemaVersion === INSTALL_MANIFEST_VERSION\n      && (v.source === \"npm\" || v.source === \"git\")\n      && Array.isArray(v.previous)\n      && typeof v.payloadPath === \"string\";\n  } catch { return false; }\n}","typeGuard":"import { INSTALL_MANIFEST_VERSION, type InstallManifest } from \"./install-store.js\";\n\nfunction isInstallManifest(value: unknown): value is InstallManifest {\n  const v = value as Record<string, unknown>;\n  return typeof v === \"object\" && v !== null\n    && v.schemaVersion === INSTALL_MANIFEST_VERSION\n    && (v.source === \"npm\" || v.source === \"git\")\n    && Array.isArray(v.previous)\n    && typeof v.payloadPath === \"string\";\n}","tryCatchPattern":"import { readInstallManifest } from \"./install-store.js\";\n\ntry {\n  const m = readInstallManifest(paths);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"Could not read managed install manifest\")) {\n    // inner cause may be 'unsupported manifest shape' (this error) — reset store\n    console.error(\"Manifest shape invalid. Reset: rm -rf ~/.paperclip/cli && paperclipai install\");\n  }\n  throw err;\n}","preventionTips":["Do not hand-edit install.json schema fields (schemaVersion, source, previous, payloadPath).","When upgrading Paperclip, check whether INSTALL_MANIFEST_VERSION changed and follow migration notes.","Restore install.json only from backups made by the same CLI version."],"tags":["install-store","manifest","validation","cli"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}