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

  1. Remove '..' segments and absolute prefixes from the relative path so it stays under the root
  2. If the target truly lives outside the root, pass the outer directory as rootDir
  3. 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

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


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/7acc073af4fc80aa. Report an issue: GitHub.