paperclipai/paperclip · error
Invalid object key.
Error message
Invalid object key.
What it means
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.
Source
Thrown at cli/src/commands/worktree.ts:299
function resolveWorktreeStartPoint(explicit?: string): string | undefined {
return explicit ?? nonEmpty(process.env.PAPERCLIP_WORKTREE_START_POINT) ?? undefined;
}
type ConfiguredStorage = {
getObject(companyId: string, objectKey: string): Promise<Buffer>;
putObject(companyId: string, objectKey: string, body: Buffer, contentType: string): Promise<void>;
};
function assertStorageCompanyPrefix(companyId: string, objectKey: string): void {
if (!objectKey.startsWith(`${companyId}/`) || objectKey.includes("..")) {
throw new Error(`Invalid object key for company ${companyId}.`);
}
}
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> {View on GitHub (pinned to 67001ec6eb)
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.
Example fix
// before
const key = normalizeStorageObjectKey(`/${userPath}`);
// after
const key = normalizeStorageObjectKey(userPath.replace(/^\/+/, '')); Defensive patterns
Strategy: validation
Validate before calling
function safeRelativeKey(raw: string): string {
const trimmed = raw.replace(/\\/g, '/').trim().replace(/^\/+/, '');
if (!trimmed) throw new Error('Object key must not be empty');
return trimmed;
}
// const key = safeRelativeKey(userPath); // guarantees non-empty, no leading slash Type guard
function isNormalizableObjectKey(raw: string): boolean {
const n = raw.replace(/\\/g, '/').trim();
return n.length > 0 && !n.startsWith('/');
} Prevention
- 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.
When it happens
Trigger: 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'.
Common situations: 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.
Related errors
- Invalid object key for company ${companyId}.
- --payload must be a JSON object
- ${name} must be a JSON object
- Invalid ${name} JSON: ${err instanceof Error ? err.message :
- --file is required
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/67db43c17da96088.
Report an issue: GitHub.