vercel/turborepo · error · Error

Invalid example name: ${name}

Error message

Invalid example name: ${name}

What it means

downloadAndExtractExample() validates the example name against /^[a-zA-Z0-9_-]+$/ before doing any work, explicitly to block path traversal (../) and git argument injection. Empty names, or names containing dots, slashes, spaces, or any character outside letters/digits/hyphen/underscore, are rejected.

Source

Thrown at packages/turbo-utils/src/examples.ts:540

  try {
    rmSync(tempDir, {
      recursive: true,
      force: true,
      maxRetries: 5,
      retryDelay: 100
    });
  } catch (error) {
    warn(
      `Unable to remove temporary directory ${tempDir}:\n${formatError(error)}`
    );
  }
}

export async function downloadAndExtractExample(root: string, name: string) {
  // Validate example name to prevent path traversal and argument injection
  // Only allow alphanumeric characters, hyphens, and underscores
  if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) {
    throw new Error(`Invalid example name: ${name}`);
  }

  // Normalize and validate the root directory to prevent unsafe git arguments
  const normalizedRoot = resolve(root);
  assertSafeGitArgument(normalizedRoot, "project root");

  const tempDir = join(normalizedRoot, ".turbo-clone-temp");
  assertSafeGitArgument(tempDir, "temporary directory");

  try {
    // Clone with partial clone (no blobs) and no checkout
    runGit([
      "clone",
      "--filter=blob:none",
      "--no-checkout",
      "--depth",
      "1",
      "--sparse",

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. Pass the bare example directory name only: 'basic', 'with-vite', not a path
  2. Normalize input before calling: name.trim().split('/').pop()
  3. For arbitrary repos or nested paths, use downloadAndExtractRepo with a repo shorthand instead

Example fix

// before
await downloadAndExtractExample(root, 'examples/basic'); // throws

// after
await downloadAndExtractExample(root, 'basic');
Defensive patterns

Strategy: validation

Validate before calling

const EXAMPLE_NAME = /^[a-zA-Z0-9_-]+$/;

function normalizeExampleName(input: string): string {
  return input.trim().split("/").pop() ?? "";
}

const name = normalizeExampleName(userInput);
if (!EXAMPLE_NAME.test(name)) throw new Error(`Unsupported example name: ${userInput}`);

Type guard

function isValidExampleName(name: string): boolean {
  return /^[a-zA-Z0-9_-]+$/.test(name);
}

Try / catch

try {
  await downloadAndExtractExample(root, name);
} catch (e) {
  if (e instanceof Error && e.message.startsWith("Invalid example name:")) {
    // re-prompt with a sanitized name or list valid examples
  } else throw e;
}

Prevention

When it happens

Trigger: Calling downloadAndExtractExample(root, name) with values like 'examples/basic', '../basic', 'basic.', 'my example', '' — anything failing the strict charset regex. Note that dots are rejected, so even plausible-looking names with '.v2' suffixes fail.

Common situations: Users pasting a path from the docs (examples/with-tailwind) instead of the bare name; scripts interpolating unsanitized user input; trailing dots or spaces from copy-paste.

Related errors


AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16). Data as JSON: /api/errors/86d8c4e25a3bbeb2. Report an issue: GitHub.