{"record":{"id":"398806495de86eb2","repo":"vercel/turborepo","slug":"invalid-description-path-must-be-an-absolute","errorCode":null,"errorMessage":"Invalid ${description}: path must be an absolute, non-empty string without NUL or newline characters and cannot start with \"-\"","messagePattern":"Invalid (.+?): path must be an absolute, non-empty string without NUL or newline characters and cannot start with \"-\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/turbo-utils/src/examples.ts","lineNumber":493,"sourceCode":"/**\n * Validates that a path is safe to use as a git CLI argument.\n * Prevents argument injection by rejecting paths that:\n * - Are empty or not a string\n * - Contain NUL bytes (could truncate the argument)\n * - Start with \"-\" (could be interpreted as a git option)\n * - Are not absolute filesystem paths (helps ensure they cannot be mistaken\n *   for URLs or additional git options like \"--upload-pack\")\n */\nfunction assertSafeGitArgument(value: string, description: string): void {\n  if (\n    !value ||\n    typeof value !== \"string\" ||\n    value.includes(\"\\0\") ||\n    value.includes(\"\\n\") ||\n    value.startsWith(\"-\") ||\n    !isAbsolute(value)\n  ) {\n    throw new Error(\n      `Invalid ${description}: path must be an absolute, non-empty string without NUL or newline characters and cannot start with \"-\"`\n    );\n  }\n}\n\nfunction formatError(error: unknown): string {\n  if (error && typeof error === \"object\" && \"stderr\" in error) {\n    const { stderr } = error as { stderr?: unknown };\n    if (typeof stderr === \"string\" || Buffer.isBuffer(stderr)) {\n      const output = stderr.toString().trim();\n      if (output) {\n        return output;\n      }\n    }\n  }\n\n  return error instanceof Error ? error.message : String(error);\n}","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/turbo-utils/src/examples.ts#L475-L511","documentation":"assertSafeGitArgument() hardens downloadAndExtractExample() against git argument injection: the resolved project root and the temp directory must be non-empty absolute strings containing no NUL or newline bytes and must not start with '-'. Any violation throws before a git command runs.","triggerScenarios":"Passing a root path that contains a newline or NUL byte (unquoted CI variables, untrimmed command substitution output, control characters pasted into scripts), or a root that does not resolve to an absolute path on the platform.","commonSituations":"CI matrix jobs interpolating unsanitized path variables; shell scripts building paths from $(cat file) without trimming; paths copied with trailing whitespace or embedded line breaks.","solutions":["Sanitize the root before calling: strip control characters (root.replace(/[\\0\\n\\r]/g, '')) and trim whitespace","Pass an absolute path: path.resolve(cwd, input) before invoking downloadAndExtractExample","Fix the upstream script or CI variable that injects the whitespace into the path"],"exampleFix":"// before\nawait downloadAndExtractExample(`${root}\\n`, name); // newline from untrimmed input\n\n// after\nconst safeRoot = path.resolve(root.replace(/[\\0\\n\\r]/g, '').trim());\nawait downloadAndExtractExample(safeRoot, name);","handlingStrategy":"validation","validationCode":"import { isAbsolute, resolve } from \"node:path\";\n\nfunction toSafeRoot(input: string): string {\n  const cleaned = input.replace(/[\\0\\n\\r]/g, \"\").trim();\n  const abs = resolve(cleaned);\n  if (!isAbsolute(abs) || abs.startsWith(\"-\")) throw new Error(`Unsafe root: ${JSON.stringify(input)}`);\n  return abs;\n}","typeGuard":"function isSafeGitPath(value: string): boolean {\n  return Boolean(value) && !value.includes(\"\\0\") && !value.includes(\"\\n\") && !value.startsWith(\"-\") && isAbsolute(value);\n}","tryCatchPattern":"try {\n  await downloadAndExtractExample(root, name);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"path must be an absolute, non-empty string\")) {\n    // your input path contains control characters or is relative — sanitize and retry\n  } else throw e;\n}","preventionTips":["Always pass path.resolve()'d absolute paths to download APIs","Trim and strip control characters from paths sourced from env vars or command substitution","Fail fast in CI on paths containing newlines (common unquoted-variable bug)"],"tags":["security","path-validation","git","input-sanitization"],"backgroundTag":"unsafe-path-argument","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}