vercel/turborepo · error · Error

Invalid ${description}: path must be an absolute, non-empty

Error message

Invalid ${description}: path must be an absolute, non-empty string without NUL or newline characters and cannot start with "-"

What it means

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.

Source

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

/**
 * Validates that a path is safe to use as a git CLI argument.
 * Prevents argument injection by rejecting paths that:
 * - Are empty or not a string
 * - Contain NUL bytes (could truncate the argument)
 * - Start with "-" (could be interpreted as a git option)
 * - Are not absolute filesystem paths (helps ensure they cannot be mistaken
 *   for URLs or additional git options like "--upload-pack")
 */
function assertSafeGitArgument(value: string, description: string): void {
  if (
    !value ||
    typeof value !== "string" ||
    value.includes("\0") ||
    value.includes("\n") ||
    value.startsWith("-") ||
    !isAbsolute(value)
  ) {
    throw new Error(
      `Invalid ${description}: path must be an absolute, non-empty string without NUL or newline characters and cannot start with "-"`
    );
  }
}

function formatError(error: unknown): string {
  if (error && typeof error === "object" && "stderr" in error) {
    const { stderr } = error as { stderr?: unknown };
    if (typeof stderr === "string" || Buffer.isBuffer(stderr)) {
      const output = stderr.toString().trim();
      if (output) {
        return output;
      }
    }
  }

  return error instanceof Error ? error.message : String(error);
}

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. Sanitize the root before calling: strip control characters (root.replace(/[\0\n\r]/g, '')) and trim whitespace
  2. Pass an absolute path: path.resolve(cwd, input) before invoking downloadAndExtractExample
  3. Fix the upstream script or CI variable that injects the whitespace into the path

Example fix

// before
await downloadAndExtractExample(`${root}\n`, name); // newline from untrimmed input

// after
const safeRoot = path.resolve(root.replace(/[\0\n\r]/g, '').trim());
await downloadAndExtractExample(safeRoot, name);
Defensive patterns

Strategy: validation

Validate before calling

import { isAbsolute, resolve } from "node:path";

function toSafeRoot(input: string): string {
  const cleaned = input.replace(/[\0\n\r]/g, "").trim();
  const abs = resolve(cleaned);
  if (!isAbsolute(abs) || abs.startsWith("-")) throw new Error(`Unsafe root: ${JSON.stringify(input)}`);
  return abs;
}

Type guard

function isSafeGitPath(value: string): boolean {
  return Boolean(value) && !value.includes("\0") && !value.includes("\n") && !value.startsWith("-") && isAbsolute(value);
}

Try / catch

try {
  await downloadAndExtractExample(root, name);
} catch (e) {
  if (e instanceof Error && e.message.includes("path must be an absolute, non-empty string")) {
    // your input path contains control characters or is relative — sanitize and retry
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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