remix-run/remix · error · Error
Resolved path escapes the allowed root: ${relativePath}
Error message
Resolved path escapes the allowed root: ${relativePath} What it means
Thrown by resolveContainedPath when the resolved absolute path falls outside the allowed root directory. The library uses it as a path-traversal guard so CLI operations (writing/reading generated files) cannot touch files outside the project root.
Source
Thrown at packages/cli/src/lib/contained-path.ts:12
import * as path from 'node:path'
export function resolveContainedPath(rootDir: string, relativePath: string): string {
let resolvedRootDir = path.resolve(rootDir)
let resolvedPath = path.resolve(resolvedRootDir, relativePath)
let pathFromRoot = path.relative(resolvedRootDir, resolvedPath)
if (pathFromRoot === '' || (!pathFromRoot.startsWith('..') && !path.isAbsolute(pathFromRoot))) {
return resolvedPath
}
throw new Error(`Resolved path escapes the allowed root: ${relativePath}`)
}
View on GitHub (pinned to 9696913134)
Solutions
- Remove '..' segments and absolute prefixes from the relative path so it stays under the root
- If the target truly lives outside the root, pass the outer directory as rootDir
- Check for symlinks inside the root that resolve outside and replace or relocate them
Example fix
// before resolveContainedPath(appRoot, '../shared/routes.ts') // after resolveContainedPath(sharedRoot, 'routes.ts')
Defensive patterns
Strategy: validation
Validate before calling
const path = require('node:path')
function isInsideRoot(root, rel) {
let resolved = path.resolve(root, rel)
return resolved === root || resolved.startsWith(root + path.sep)
}
if (!isInsideRoot(appRoot, relativePath)) throw new Error('reject before calling') Prevention
- Normalize user paths with path.normalize before passing
- Reject absolute paths and '..' segments at input boundaries
- Treat symlinks as untrusted; use fs.realpath before containment checks
When it happens
Trigger: Calling resolveContainedPath(rootDir, relativePath) where relativePath (after resolving symlinks/absolute segments) points outside rootDir, e.g. '../../etc/passwd', an absolute path like '/etc/hosts', or a symlink inside the root that resolves elsewhere.
Common situations: User-supplied or config-derived paths (e.g. from remix.json) containing '../' segments, absolute paths, or symlinks pointing outside the app; generating routes to a path like '../shared/routes'.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Doctor fix path resolves outside the app root: ${fixPath}
- Expected a Remix config file or directory: ${fromPath}
- RMX_TARGET_DIRECTORY_NOT_EMPTY
- RMX_TARGET_PATH_NOT_DIRECTORY
- Could not determine an app name from the target directory.
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/7acc073af4fc80aa.
Report an issue: GitHub.