{"record":{"id":"67db43c17da96088","repo":"paperclipai/paperclip","slug":"invalid-object-key","errorCode":null,"errorMessage":"Invalid object key.","messagePattern":"Invalid object key\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/worktree.ts","lineNumber":299,"sourceCode":"function resolveWorktreeStartPoint(explicit?: string): string | undefined {\n  return explicit ?? nonEmpty(process.env.PAPERCLIP_WORKTREE_START_POINT) ?? undefined;\n}\n\ntype ConfiguredStorage = {\n  getObject(companyId: string, objectKey: string): Promise<Buffer>;\n  putObject(companyId: string, objectKey: string, body: Buffer, contentType: string): Promise<void>;\n};\n\nfunction assertStorageCompanyPrefix(companyId: string, objectKey: string): void {\n  if (!objectKey.startsWith(`${companyId}/`) || objectKey.includes(\"..\")) {\n    throw new Error(`Invalid object key for company ${companyId}.`);\n  }\n}\n\nfunction normalizeStorageObjectKey(objectKey: string): string {\n  const normalized = objectKey.replace(/\\\\/g, \"/\").trim();\n  if (!normalized || normalized.startsWith(\"/\")) {\n    throw new Error(\"Invalid object key.\");\n  }\n  const parts = normalized.split(\"/\").filter((part) => part.length > 0);\n  if (parts.length === 0 || parts.some((part) => part === \".\" || part === \"..\")) {\n    throw new Error(\"Invalid object key.\");\n  }\n  return parts.join(\"/\");\n}\n\nfunction resolveLocalStoragePath(baseDir: string, objectKey: string): string {\n  const resolved = path.resolve(baseDir, normalizeStorageObjectKey(objectKey));\n  const root = path.resolve(baseDir);\n  if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {\n    throw new Error(\"Invalid object key path.\");\n  }\n  return resolved;\n}\n\nasync function s3BodyToBuffer(body: unknown): Promise<Buffer> {","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/worktree.ts#L281-L317","documentation":"Thrown by normalizeStorageObjectKey when, after backslash-to-slash conversion and trimming, the key is empty or begins with a forward slash. An empty key has no target object; a leading slash would produce an absolute path that escapes the company-prefixed namespace. This is the first of two normalization guards inside the function.","triggerScenarios":"Calling normalizeStorageObjectKey (directly or via resolveLocalStoragePath / storage get-put) with '', '   ', '/abs/path', or a backslash-only input that trims to empty. The leading-slash branch rejects keys like '/foo/bar'.","commonSituations":"Constructing a key from an unset env var or empty form field. Concatenating path segments with a leading separator by mistake (`/${file}`). Receiving a Windows absolute path ('C:\\...') that normalizes to a leading slash form.","solutions":["Pass a non-empty relative key: normalizeStorageObjectKey('attachments/file.png').","Trim and strip any leading slash before calling: key.replace(/^\\/+/, '').","Guard upstream: if (!key || !key.trim()) throw a clearer validation error first."],"exampleFix":"// before\nconst key = normalizeStorageObjectKey(`/${userPath}`);\n// after\nconst key = normalizeStorageObjectKey(userPath.replace(/^\\/+/, ''));","handlingStrategy":"validation","validationCode":"function safeRelativeKey(raw: string): string {\n  const trimmed = raw.replace(/\\\\/g, '/').trim().replace(/^\\/+/, '');\n  if (!trimmed) throw new Error('Object key must not be empty');\n  return trimmed;\n}\n// const key = safeRelativeKey(userPath);  // guarantees non-empty, no leading slash","typeGuard":"function isNormalizableObjectKey(raw: string): boolean {\n  const n = raw.replace(/\\\\/g, '/').trim();\n  return n.length > 0 && !n.startsWith('/');\n}","tryCatchPattern":null,"preventionTips":["Strip leading slashes and trim before constructing object keys.","Reject empty keys upstream with a clearer domain-specific error.","When joining path segments, use a helper that drops empty parts instead of string concatenation."],"tags":["validation","storage","object-key"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}