mastra-ai/mastra · error

Worker ${label} must stay within the deployed artifact root.

Error message

Worker ${label} must stay within the deployed artifact root.

What it means

validateRelativePath requires a path used inside the deployed worker artifact to be non-empty, relative, and not escape the artifact root after normalization. It guards workingDirectory and file-type worker input paths so uploads and cd targets can never resolve outside the deployed directory (path traversal defense).

Source

Thrown at deployers/sandbox/src/worker.ts:206

    for (const name of Object.keys(resourceLimits)) {
      if (!knownLimits.has(name)) throw new Error(`Unknown worker resource limit: ${name}.`);
    }
    for (const [name, value] of [
      ['cpuTimeSeconds', resourceLimits.cpuTimeSeconds],
      ['addressSpaceBytes', resourceLimits.addressSpaceBytes],
      ['fileSizeBytes', resourceLimits.fileSizeBytes],
      ['openFiles', resourceLimits.openFiles],
    ] as const) {
      if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0)) {
        throw new Error(`Worker resourceLimits.${name} must be a positive safe integer.`);
      }
    }
  }
}

function validateRelativePath(value: string, label: string): void {
  if (!value || posix.isAbsolute(value) || posix.normalize(value).startsWith('..')) {
    throw new Error(`Worker ${label} must stay within the deployed artifact root.`);
  }
}

function validateInput(input: SandboxWorkerInput | undefined): void {
  if (input?.type === 'file') validateRelativePath(input.path, 'input file path');
}

function normalizeResourceLimits(
  limits: SandboxWorkerResourceLimits | undefined,
): NormalizedResourceLimits | undefined {
  if (!limits || Object.values(limits).every(value => value === undefined)) return undefined;
  return {
    cpuTimeSeconds: limits.cpuTimeSeconds,
    addressSpaceBytes: limits.addressSpaceBytes,
    addressSpaceKilobytes:
      limits.addressSpaceBytes === undefined ? undefined : Math.floor(limits.addressSpaceBytes / 1024),
    fileSizeBytes: limits.fileSizeBytes,
    fileSizeBlocks: limits.fileSizeBytes === undefined ? undefined : Math.floor(limits.fileSizeBytes / 512),

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use a relative path such as '.', 'dist', or 'bin/server.js' that resolves inside the artifact you deploy in dir.
  2. Strip leading slashes and resolve '..' segments against your intended base before calling, or use posix.resolve(base, p) and verify the result starts with the base.
  3. For data living outside the artifact, stage it as stdin input (input: { type: 'stdin', data }) instead of a file path.
  4. For relaunch input, ensure the file path is relative to the original remoteDir, not the host filesystem.

Example fix

// before
await deployWorkerToSandbox({ sandbox, dir: './worker', command: 'node', workingDirectory: '/opt/worker/dist' });
await deployWorkerToSandbox({ sandbox, dir: './worker', command: 'node', input: { type: 'file', path: '../payload.json' } });
// after
await deployWorkerToSandbox({ sandbox, dir: './worker', command: 'node', workingDirectory: 'dist' });
await deployWorkerToSandbox({ sandbox, dir: './worker', command: 'node', input: { type: 'file', path: 'payload.json' } });
Defensive patterns

Strategy: validation

Validate before calling

import { posix } from 'node:path';
function assertSafeRelativePath(value, label) {
  if (!value || posix.isAbsolute(value) || posix.normalize(value).startsWith('..')) {
    throw new Error(`${label} must be a relative path inside the artifact root, got: ${value}`);
  }
}
assertSafeRelativePath(options.workingDirectory ?? '.', 'workingDirectory');
if (options.input?.type === 'file') assertSafeRelativePath(options.input.path, 'input path');

Type guard

function isSafeRelativePath(value) {
  return typeof value === 'string' && value.length > 0 &&
    !posix.isAbsolute(value) && !posix.normalize(value).startsWith('..');
}

Try / catch

try {
  await deployWorkerToSandbox(options);
} catch (error) {
  if (error instanceof Error && error.message.includes('must stay within the deployed artifact root')) {
    console.error(`Make ${error.message.match(/Worker (.+) must/)?.[1]} a relative path like 'dist' or 'data/input.json'`);
  } else throw error;
}

Prevention

When it happens

Trigger: Passing deployWorkerToSandbox options.workingDirectory = '/app' (absolute), '' (empty), or '../shared'; or passing input: { type: 'file', path: '../../etc/passwd' } (also via deployment.relaunch({ input }) which re-validates). Any path whose posix.normalize starts with '..' triggers it.

Common situations: Using an absolute host path copied from local machine config; building paths with string concatenation where a parent dir slips in ('..' segments); defaulting to '' when a config key is missing; trying to mount or read shared files outside the artifact root; Windows-style absolute paths like 'C:\data' after normalization still count as relative but leading-slash POSIX paths do not.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/e3d60d0b78db4333. Report an issue: GitHub.