paperclipai/paperclip · error · Error
Invalid object key path.
Error message
Invalid object key path.
What it means
Thrown by resolveLocalStoragePath when an object key, after normalization and path.resolve against baseDir, escapes the storage root directory. This is a path-traversal guard ensuring local_disk storage writes/reads stay confined under the configured baseDir. It fires only when the resolved path is neither exactly the root nor a child of root plus a path separator.
Source
Thrown at cli/src/commands/worktree.ts:312
}
function normalizeStorageObjectKey(objectKey: string): string {
const normalized = objectKey.replace(/\\/g, "/").trim();
if (!normalized || normalized.startsWith("/")) {
throw new Error("Invalid object key.");
}
const parts = normalized.split("/").filter((part) => part.length > 0);
if (parts.length === 0 || parts.some((part) => part === "." || part === "..")) {
throw new Error("Invalid object key.");
}
return parts.join("/");
}
function resolveLocalStoragePath(baseDir: string, objectKey: string): string {
const resolved = path.resolve(baseDir, normalizeStorageObjectKey(objectKey));
const root = path.resolve(baseDir);
if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {
throw new Error("Invalid object key path.");
}
return resolved;
}
async function s3BodyToBuffer(body: unknown): Promise<Buffer> {
if (!body) {
throw new Error("Object not found.");
}
if (Buffer.isBuffer(body)) {
return body;
}
if (body instanceof Readable) {
return await streamToBuffer(body);
}
const candidate = body as {
transformToWebStream?: () => ReadableStream<Uint8Array>;
arrayBuffer?: () => Promise<ArrayBuffer>;View on GitHub (pinned to 67001ec6eb)
Solutions
- Ensure config.storage.localDisk.baseDir is an absolute, canonical path (no symlinks) matching the runtime filesystem layout.
- Sanitize objectKey with path.normalize and strip leading separators before passing it to getObject/putObject.
- Verify the companyId prefix and reject any objectKey containing absolute paths or alternate roots before calling storage.
- If baseDir is symlinked, resolve it to realpath once at config load and reuse the canonical form.
Example fix
// before const baseDir = config.storage.localDisk.baseDir; // after const baseDir = fs.realpathSync(expandHomePrefix(config.storage.localDisk.baseDir));
Defensive patterns
Strategy: validation
Validate before calling
function isSafeObjectKey(baseDir: string, objectKey: string): boolean {
try {
const root = fs.realpathSync(path.resolve(baseDir));
const resolved = path.resolve(root, objectKey.replace(/\\/g, '/'));
return resolved === root || resolved.startsWith(root + path.sep);
} catch {
return false;
}
}
// before storage.getObject/putObject:
if (!isSafeObjectKey(baseDir, key)) throw new Error('Refusing unsafe object key'); Type guard
function isConfinedPath(root: string, target: string): boolean {
const r = path.resolve(root);
const t = path.resolve(target);
return t === r || t.startsWith(r + path.sep);
} Try / catch
try {
await storage.putObject(companyId, key, buf, ct);
} catch (e) {
if (e instanceof Error && e.message === 'Invalid object key path.') {
// reject the key client-side, log security event
} else throw e;
} Prevention
- Canonicalize baseDir with realpathSync at config load.
- Reject object keys containing absolute paths, drive letters, or UNC prefixes before storage calls.
- Unit-test path traversal vectors (.., %2e%2e, symlinks) against the storage layer.
When it happens
Trigger: Calling ConfiguredStorage.getObject/putObject on a local_disk provider with an objectKey whose normalized form resolves outside baseDir (e.g. an absolute path on another drive, or a key that after normalizeStorageObjectKey still resolves upward via symlinks). The earlier normalizeStorageObjectKey blocks literal '..' segments, so this is the second-line defense for OS-level path resolution discrepancies (Windows drive letters, case-insensitive roots, symlinked baseDir).
Common situations: baseDir configured as a relative or symlinked path that does not match its realpath; cross-platform path separators on Windows; object keys containing drive letters or UNC paths that slip past the string-based checks; baseDir moved or renamed after config write.
Related errors
- Invalid object key for company ${companyId}.
- Refusing to write export file outside output directory: ${re
- Object not found.
- Refusing to use non-directory install-store path ${directory
- Refusing to modify path not owned by the current user: ${tar
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/b41b517275014e06.
Report an issue: GitHub.