mastra-ai/mastra · error

Invalid checkpoint name: ${name}

Error message

Invalid checkpoint name: ${name}

What it means

LocalSandbox._checkpointPath() resolves the on-disk directory for a named checkpoint and rejects unsafe names. A valid name starts with an alphanumeric character and contains only [A-Za-z0-9._-], and may not contain `..` anywhere. This prevents path traversal via checkpoint names when they're joined into the checkpoints directory.

Source

Thrown at packages/core/src/workspace/sandbox/local-sandbox.ts:405

        this._seatbeltProfilePath = path.join(this._sandboxFolderPath, `seatbelt-${configHash}.sb`);
        await fs.writeFile(this._seatbeltProfilePath, generatedProfile, 'utf-8');
      }
    }

    this.logger.debug('Sandbox started', { workingDirectory: this.workingDirectory });
  }

  // ---------------------------------------------------------------------------
  // Checkpoints
  // ---------------------------------------------------------------------------

  /** LocalSandbox persists real filesystem-backed checkpoints. */
  readonly supportsCheckpoints = true;

  /** Resolve the on-disk directory for a named checkpoint, rejecting unsafe names. */
  private _checkpointPath(name: string): string {
    if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) || name.includes('..')) {
      throw new Error(`Invalid checkpoint name: ${name}`);
    }
    return path.join(this._checkpointsDirectory, name);
  }

  /**
   * Seed an empty/missing working directory from the configured checkpoint.
   * Missing checkpoint or already-populated workdir → no-op (normal start).
   */
  private async _seedFromCheckpoint(): Promise<void> {
    if (!this._checkpointName && !this._seedCheckpointName) return;

    // Only seed an empty working directory; a populated one wins.
    const entries = await fs.readdir(this.workingDirectory).catch(() => []);
    if (entries.length > 0) return;

    // Prefer the primary checkpoint; fall back to the boot-only seed checkpoint.
    const candidates = [this._checkpointName, this._seedCheckpointName].filter(
      (name): name is string => name !== undefined,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Sanitize the name to the allowed pattern: /^[A-Za-z0-9][A-Za-z0-9._-]*$/ (no slashes, spaces, or `..`)
  2. Derive names programmatically, e.g. slugify or Date.now()-based names like `cp-1724912345`
  3. Validate before calling any checkpoint API and show a clear message to the user when their input is invalid

Example fix

// before
sandbox.checkpointDir(featureBranchName); // 'feat/my-branch' throws
// after
const safeName = 'cp-' + featureBranchName.replace(/[^A-Za-z0-9._-]/g, '-').replace(/^[^A-Za-z0-9]/, 'x');
sandbox.checkpointDir(safeName);
Defensive patterns

Strategy: validation

Validate before calling

export function toSafeCheckpointName(raw: string): string {
  const name = raw.replace(/[^A-Za-z0-9._-]/g, '-').replace(/\.+/g, '.').replace(/^[^A-Za-z0-9]/, 'x');
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) || name.includes('..')) throw new Error(`Invalid checkpoint name: ${raw}`);
  return name;
}

Try / catch

try {
  const dir = sandbox.checkpointDir(name);
} catch (err) {
  if (/Invalid checkpoint name/.test(String(err?.message))) {
    throw new Error(`Checkpoint names must match [A-Za-z0-9][A-Za-z0-9._-]*; got: ${name}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling checkpoint-related APIs (checkpointDir, target, restore flows) with a name like `../../etc`, `my checkpoint` (space), `#draft`, an empty string, or any name with slashes/unicode.

Common situations: Generating checkpoint names from user input, branch names, or timestamps containing `/` or spaces; using identifiers with `#` or `:`; forgotten sanitization when checkpoint names come from API consumers.

Related errors


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