{"record":{"id":"2bc006ece8f1da64","repo":"paperclipai/paperclip","slug":"invalid-install-payload-identifier-identifier","errorCode":null,"errorMessage":"Invalid install payload identifier '${identifier}'.","messagePattern":"Invalid install payload identifier '(.+?)'\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/install-store.ts","lineNumber":210,"sourceCode":"    return await callback();\n  } finally {\n    try {\n      if (fs.readFileSync(paths.lockPath, \"utf8\").trim() === token) {\n        fs.rmSync(paths.lockPath, { force: true });\n      }\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n    }\n  }\n}\n\nexport function payloadPathFor(\n  paths: InstallStorePaths,\n  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;","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/install-store.ts#L192-L228","documentation":"Thrown by payloadPathFor() when the supplied identifier does not match the regex /^[A-Za-z0-9._-]+$/. Identifiers are joined into filesystem paths under installsRoot, so they must be safe single-segment names — no slashes, spaces, colons, or shell metacharacters — to prevent path traversal and traversal-adjacent issues.","triggerScenarios":"Called payloadPathFor(paths, source, identifier) with an identifier containing characters outside [A-Za-z0-9._-], e.g. a version like '1.2.3/beta', '1.2.3:rc1', a path with spaces, or an empty string.","commonSituations":"1) Passing a git ref containing a slash (e.g. 'feature/foo') as the identifier. 2) Passing a version with a prerelease tag separator not in the allowed set (e.g. '1.0.0+build' is fine but '1.0.0 rc1' is not). 3) Passing a relative path like '../x' or an absolute path. 4) Empty or whitespace-only identifier.","solutions":["Sanitize the identifier to only contain A-Z, a-z, 0-9, '.', '_', '-' before calling payloadPathFor.","Replace slashes in git refs/branches with a safe separator like '-' (e.g. 'feature-foo') before use.","Use the version string directly (semver versions already match the regex).","Reject empty identifiers upstream before reaching this call."],"exampleFix":"// before\npayloadPathFor(paths, \"git\", \"feature/auth\");  // throws: '/' not allowed\n\n// after\nconst safeId = \"feature/auth\".replace(/[^A-Za-z0-9._-]/g, \"-\"); // \"feature-auth\"\npayloadPathFor(paths, \"git\", safeId);","handlingStrategy":"validation","validationCode":"function isValidPayloadIdentifier(id: string): boolean {\n  return typeof id === \"string\" && /^[A-Za-z0-9._-]+$/.test(id);\n}\n\n// Before calling payloadPathFor:\nif (!isValidPayloadIdentifier(id)) throw new Error(`Bad payload id: ${id}`);","typeGuard":"function isPayloadIdentifier(value: unknown): value is string {\n  return typeof value === \"string\" && /^[A-Za-z0-9._-]+$/.test(value);\n}","tryCatchPattern":"try {\n  payloadPathFor(paths, source, id);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Invalid install payload identifier\")) {\n    const safe = id.replace(/[^A-Za-z0-9._-]/g, \"-\");\n    payloadPathFor(paths, source, safe);\n  } else throw err;\n}","preventionTips":["Sanitize git refs/branches (replace '/' with '-') before using as identifier.","Prefer semver version strings, which already match the allowed character set.","Reject empty identifiers upstream.","Never derive identifiers from raw filesystem paths or URLs."],"tags":["install-store","validation","path-traversal","cli"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}