vercel/ai · error

Sandbox workspace mirror received an invalid relative path:

Error message

Sandbox workspace mirror received an invalid relative path: ${inputPath}

What it means

normalizeRelativePath in the sandbox workspace mirror validates that every path it mirrors is a safe relative path inside the workspace. It rejects empty paths, '.', '..', absolute paths, and any path escaping the root via a leading '..' segment. This prevents the mirror from reading or writing files outside the sandboxed workspace directory.

Source

Thrown at packages/harness-pi/src/pi-workspace-mirror.ts:45

 * copied as real files. `.agents/skills` is frequently a symlink to a `skills`
 * directory living elsewhere in the workspace; a mirrored symlink would dangle
 * because its target falls outside the scoped mirror, so the linked content is
 * walked and copied verbatim instead.
 */
const PI_CONFIG_DIRS = ['.pi', '.agents'] as const;
const PI_CONTEXT_FILENAMES = ['AGENTS.md', 'AGENTS.MD'] as const;

function normalizeRelativePath(inputPath: string): string {
  const normalized = inputPath.split(path.posix.sep).join(path.sep);
  const relative = path.normalize(normalized);
  if (
    relative === '' ||
    relative === '.' ||
    path.isAbsolute(relative) ||
    relative === '..' ||
    relative.startsWith(`..${path.sep}`)
  ) {
    throw new Error(
      `Sandbox workspace mirror received an invalid relative path: ${inputPath}`,
    );
  }
  return relative;
}

async function readCommandOutput(
  sandbox: Experimental_SandboxSession,
  command: string,
): Promise<string> {
  const result = await sandbox.run({ command });
  if (result.exitCode != null && result.exitCode !== 0) {
    throw new Error(
      result.stderr ||
        result.stdout ||
        `Sandbox command failed with exit code ${result.exitCode}`,
    );
  }

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Convert the input to a workspace-relative path before handing it to the mirror (e.g. path.relative(workspaceRoot, absPath)).
  2. Verify the workspace root is correct so relative resolution does not yield '..' segments.
  3. Normalize and strip leading separators; reject or remap absolute inputs at your API boundary.
  4. Catch the error and skip/skip-log the offending path rather than failing the whole mirror operation.

Example fix

// before
mirror.current({ path: '/home/me/project/src/index.ts' });
// after
const rel = path.relative(workspaceRoot, '/home/me/project/src/index.ts');
mirror.current({ path: rel }); // 'src/index.ts'
Defensive patterns

Strategy: validation

Validate before calling

const path = require('node:path');
function toWorkspaceRelative(inputPath, workspaceRoot) {
  const rel = path.isAbsolute(inputPath)
    ? path.relative(workspaceRoot, inputPath)
    : inputPath;
  if (rel === '' || rel === '.' || path.isAbsolute(rel) || rel === '..' || rel.startsWith(`..${path.sep}`)) {
    throw new Error(`Path escapes workspace: ${inputPath}`);
  }
  return rel;
}

Try / catch

try {
  await mirror.current({ path: rel });
} catch (err) {
  if (String(err.message).includes('invalid relative path')) {
    logger.warn('Skipping path outside workspace:', err.message);
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling normalizeRelativePath (via relativePath/buildRequiredDirectories/current/normalizedPath call paths) with an absolute path like '/etc/passwd', a traversal path like '../secrets.txt', or an empty/'.' value as inputPath.

Common situations: Passing OS-absolute paths from file pickers or CLI args instead of workspace-relative ones; joining paths with '..' to 'reuse' a base directory; Windows-style backslash paths that resolve as absolute on the host; misconfigured workspace root causing computed relative paths to start with '..'.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/5aee5d1c5bef4a9e. Report an issue: GitHub.