remotion-dev/remotion · error · Error
Invalid public file path: ${path}
Error message
Invalid public file path: ${path} What it means
Browser Studio normalizes every public/static file path by stripping a single leading slash and then rejecting anything that is empty, contains a backslash, contains a NUL byte, or has any segment equal to '', '.' or '..'. This keeps public-file keys canonical and blocks path traversal / escapes. The throw happens during any operation that funnels a path through normalizePublicFilePath (canonicalization, add, rename, etc.).
Source
Thrown at packages/browser-studio/src/browser-studio-project-controller.ts:41
fileName: string;
mutate: (project: VirtualProject) => VirtualProject;
nodePathMutationFiles: ProjectNodePathMutationFiles | null;
};
const MAX_HISTORY_ENTRIES = 100;
const normalizePublicFilePath = (path: string) => {
const withoutLeadingSlash = path.startsWith('/') ? path.slice(1) : path;
if (
withoutLeadingSlash.length === 0 ||
withoutLeadingSlash.includes('\\') ||
withoutLeadingSlash.includes('\0') ||
withoutLeadingSlash
.split('/')
.some((segment) => segment === '' || segment === '.' || segment === '..')
) {
throw new Error(`Invalid public file path: ${path}`);
}
return withoutLeadingSlash;
};
const getCanonicalPublicFiles = (project: VirtualProject) => {
const canonicalFiles: Record<string, Uint8Array | string> = {};
for (const [path, contents] of Object.entries(project.publicFiles ?? {})) {
const canonicalPath = normalizePublicFilePath(path);
if (Object.hasOwn(canonicalFiles, canonicalPath)) {
throw new Error(`Multiple public files resolve to ${canonicalPath}`);
}
canonicalFiles[canonicalPath] = contents;
}
return canonicalFiles;View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Sanitize the path client-side before calling the operation: strip a leading '/', replace backslashes with '/', and reject empty/dot/dot-dot segments.
- Use forward-slash, single-segment-relative paths consistently (e.g. 'images/logo.png').
- Add a UI validation layer that mirrors these rules and disables the submit button on invalid input.
- If the path comes from user input, trim it and confirm it is non-empty before submission.
Example fix
// before
renameStaticFile({oldRelativePath: '/assets/../etc/file', newRelativePath: 'out'});
// after
const safe = (p: string) => p.replace(/^\//, '').replace(/\\/g, '/');
renameStaticFile({oldRelativePath: safe('assets/file'), newRelativePath: 'out'}); Defensive patterns
Strategy: validation
Validate before calling
const isValidPublicFilePath = (raw: string): boolean => {
const p = raw.startsWith('/') ? raw.slice(1) : raw;
if (p.length === 0 || p.includes('\\') || p.includes('\0')) return false;
return p.split('/').every((seg) => seg !== '' && seg !== '.' && seg !== '..');
};
// guard every call site:
if (!isValidPublicFilePath(userPath)) throw new Error(`Refusing invalid path: ${userPath}`); Type guard
const isCanonicalPublicPath = (p: string): boolean => {
if (p.startsWith('/') || p.includes('\\') || p.includes('\0')) return false;
return p.length > 0 && p.split('/').every((s) => s !== '' && s !== '.' && s !== '..');
}; Prevention
- Sanitize paths at the UI boundary before they reach Browser Studio operations.
- Normalize once and store the canonical form; never re-introduce leading slashes or backslashes.
- Treat any path containing '..', a NUL byte, or a backslash as invalid by default.
- Add client-side validation mirroring normalizePublicFilePath so users get early feedback.
When it happens
Trigger: Calling a Browser Studio file operation with paths like '' (empty), '/' (becomes empty after strip), 'a//b' (empty segment), 'a/./b' or 'a/../b' (dot/dot-dot), 'a\\b' (Windows backslash), or a path containing a NUL character. Also when the UI forwards an untrimmed or programmatically-constructed string.
Common situations: Front-end passing a raw input without sanitizing; user typing a Windows-style path; code joining segments producing double slashes; accidental or malicious traversal attempts; trailing slashes producing an empty final segment.
Related errors
- ${oldRelativePath} does not exist
- ${newRelativePath} already exists
- The public directory was specified as "${p}", which is the r
- No 'secret' was provided to validateWebhookSignature().
- No 'body' was provided to validateWebhookSignature().
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/146a190f2e589076.
Report an issue: GitHub.