{"record":{"id":"86d8c4e25a3bbeb2","repo":"vercel/turborepo","slug":"invalid-example-name-name","errorCode":null,"errorMessage":"Invalid example name: ${name}","messagePattern":"Invalid example name: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/turbo-utils/src/examples.ts","lineNumber":540,"sourceCode":"  try {\n    rmSync(tempDir, {\n      recursive: true,\n      force: true,\n      maxRetries: 5,\n      retryDelay: 100\n    });\n  } catch (error) {\n    warn(\n      `Unable to remove temporary directory ${tempDir}:\\n${formatError(error)}`\n    );\n  }\n}\n\nexport async function downloadAndExtractExample(root: string, name: string) {\n  // Validate example name to prevent path traversal and argument injection\n  // Only allow alphanumeric characters, hyphens, and underscores\n  if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) {\n    throw new Error(`Invalid example name: ${name}`);\n  }\n\n  // Normalize and validate the root directory to prevent unsafe git arguments\n  const normalizedRoot = resolve(root);\n  assertSafeGitArgument(normalizedRoot, \"project root\");\n\n  const tempDir = join(normalizedRoot, \".turbo-clone-temp\");\n  assertSafeGitArgument(tempDir, \"temporary directory\");\n\n  try {\n    // Clone with partial clone (no blobs) and no checkout\n    runGit([\n      \"clone\",\n      \"--filter=blob:none\",\n      \"--no-checkout\",\n      \"--depth\",\n      \"1\",\n      \"--sparse\",","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/packages/turbo-utils/src/examples.ts#L522-L558","documentation":"downloadAndExtractExample validates the example name against /^[a-zA-Z0-9_-]+$/ before using it in a git sparse-checkout path. Names with slashes, dots, spaces, or any non [A-Za-z0-9_-] character are rejected. This prevents path traversal (../) and git argument injection when the name is interpolated into clone paths.","triggerScenarios":"Passing an example name like 'examples/basic-app', 'apps/web..', '../evil', 'basic app', or an empty string to downloadAndExtractExample (or create-turbo --example with a nested path instead of a bare directory name under examples/).","commonSituations":"Users copying a path from the turborepo repo (examples/my-app) instead of the bare name (my-app), passing a URL where a name is expected, or scripts that forward un sanitized argv into the example parameter.","solutions":["Use the bare directory name of the example, e.g. 'with-react-native-web' not 'examples/with-react-native-web'","For a full custom repo/path, pass the GitHub URL form instead of a nested example path","If creating your own template tree, keep example directory names alphanumeric with - and _ only","List valid names from the examples directory or the create-turbo prompts"],"exampleFix":"# before\npnpm create turbo@latest --example examples/with-vite\n# Error: Invalid example name: examples/with-vite\n\n# after\npnpm create turbo@latest --example with-vite","handlingStrategy":"validation","validationCode":"const EXAMPLE_NAME_RE = /^[a-zA-Z0-9_-]+$/;\n\nfunction isValidExampleName(name: string): boolean {\n  return EXAMPLE_NAME_RE.test(name);\n}\n// if (!isValidExampleName(name)) suggest examples from the registry instead;","typeGuard":"function isExampleName(name: string): name is string {\n  return /^[a-zA-Z0-9_-]+$/.test(name);\n}","tryCatchPattern":null,"preventionTips":["Accept only bare directory names for --example; reject slashes/dots at the CLI boundary","When users paste 'examples/foo', strip the leading 'examples/' segment automatically","Use existsInRepo(name) to check availability before attempting the download"],"tags":["validation","cli","path-traversal","create-turbo","input-validation"],"backgroundTag":"invalid-input-validation","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}