amruthpillai/reactive-resume · error · Error
Invalid storage key
Error message
Invalid storage key
What it means
LocalStorageService.resolvePath throws when, after stripping leading slashes and filtering out empty/. /.. segments, no segments remain. This means the key resolves to the storage root itself and is rejected to prevent operating on the root directory. Generic Error (surfaces as 500).
Source
Thrown at packages/api/src/features/storage/service.ts:220
message: "Local filesystem storage is accessible and has read/write permission.",
};
} catch (error: unknown) {
return {
type: "local",
status: "unhealthy",
message: "Local filesystem storage is not accessible or lacks sufficient permissions.",
error: error instanceof Error ? error.message : "Unknown error",
};
}
}
private resolvePath(key: string): string {
const normalizedKey = key.replace(/^\/*/, "");
const segments = normalizedKey
.split(/[/\\]+/)
.filter((segment) => segment.length > 0 && segment !== "." && segment !== "..");
if (segments.length === 0) throw new Error("Invalid storage key");
return join(this.rootDirectory, ...segments);
}
}
class S3StorageService implements StorageService {
private readonly bucket: string;
private readonly client: S3Client;
constructor() {
if (!env.S3_ACCESS_KEY_ID || !env.S3_SECRET_ACCESS_KEY || !env.S3_BUCKET) {
throw new Error("S3 credentials are not set");
}
this.bucket = env.S3_BUCKET;
this.client = new S3Client({
region: env.S3_REGION,
forcePathStyle: env.S3_FORCE_PATH_STYLE,View on GitHub (pinned to 3a5b12e2a4)
Solutions
- Validate the key is non-empty and contains at least one real path segment before calling storage methods.
- Trace where the blank key originated — typically a missing field on the upload metadata or a default-empty config value.
- Add a unit test on resolvePath for '', '/', '.', '..', '..' to lock in the contract.
- If a legitimate operation targets a directory prefix (list), use list(prefix) which accepts a prefix, not write/read/delete with an empty key.
Example fix
// before: passing an unvalidated key
await storage.write({ key: maybeBlank, data, contentType });
// after: guard the key
function safeKey(key: string): string {
const cleaned = key.replace(/^\/+/, '').split(/[/\\]+/).filter(s => s && s !== '.' && s !== '..').join('/');
if (!cleaned) throw new TypeError('storage key must have at least one path segment');
return cleaned;
} Defensive patterns
Strategy: validation
Validate before calling
function assertStorageKey(key: string): string {
const segs = key.replace(/^\/+/, '').split(/[/\\]+/).filter(s => s && s !== '.' && s !== '..');
if (segs.length === 0) throw new TypeError('storage key must contain at least one segment');
return segs.join('/');
} Type guard
function isValidStorageKey(key: string): key is string {
return assertStorageKey.length > 0 && /[^./\\]/.test(key.replace(/^[./\\]+/, ''));
} Prevention
- Validate keys at the call site, not just inside the storage layer.
- Never pass a default-empty variable as a key.
- Unit-test resolvePath against '', '/', '.', '..'.
When it happens
Trigger: Passing an empty string key; a key of only slashes ('///'); a key composed solely of '.'/'..' segments; a key that normalized to nothing (e.g. all segments filtered).
Common situations: Bug in caller that builds the key from an undefined/blank variable; a code path that passes a prefix instead of a full key; an upstream normalize step that collapsed the key to empty.
Related errors
- Private storage writes are not supported by the local filesy
- BAD_REQUEST
- BAD_REQUEST
- BAD_REQUEST
- BAD_REQUEST
AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12).
Data as JSON: /api/errors/2058c5b7c86575b5.
Report an issue: GitHub.