vercel/turborepo · warning · Error

`git ${args[0]}` failed: ${formatError(error)}

Error message

`git ${args[0]}` failed:
${formatError(error)}

What it means

runGit() executes git via execFileSync (clone --filter=blob:none, sparse-checkout, checkout) and wraps any failure — non-zero exit, git missing from PATH (ENOENT), or a killed process — as `git <subcommand> failed:` plus stderr or the error message. downloadAndExtractExample catches this and falls back to tarball download, so the message usually appears inside the 'Git download failed' warning rather than escaping to the caller.

Source

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

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);
}

function runGit(args: Array<string>, cwd?: string): void {
  try {
    execFileSync("git", args, { cwd, stdio: "pipe" });
  } catch (error) {
    throw new Error(`\`git ${args[0]}\` failed:\n${formatError(error)}`);
  }
}

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

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. Install git and confirm `git --version` works in the same shell/PATH
  2. Remove a stale <root>/.turbo-clone-temp directory left by an earlier failed run
  3. Read the embedded stderr — it is git's real complaint (auth, DNS, index.lock)
  4. If git is intentionally unavailable, rely on the automatic tarball fallback; only its failure is fatal

Example fix

# before: git missing in minimal container
FROM node:22-slim
# downloadAndExtractExample warns 'Git download failed' and falls back

# after
RUN apt-get update && apt-get install -y git
Defensive patterns

Strategy: try-catch

Validate before calling

import { execFileSync } from "node:child_process";

function gitAvailable(): boolean {
  try {
    execFileSync("git", ["--version"], { stdio: "pipe" });
    return true;
  } catch {
    return false;
  }
}

Type guard

function isGitFailure(e: unknown): boolean {
  return e instanceof Error && e.message.startsWith("`git ") && e.message.includes("` failed:");
}

Try / catch

// downloadAndExtractExample already falls back to tarball; wrap the outer call for the rare
// case where BOTH git and the fallback fail:
try {
  await downloadAndExtractExample(root, name);
} catch (e) {
  if (isGitFailure(e) || e.message.startsWith("Failed to download:")) {
    // report stderr embedded in the message; suggest installing git / checking network
  }
}

Prevention

When it happens

Trigger: git not installed (spawn ENOENT); clone failing due to network/DNS restrictions; sparse-checkout failing because examples/<name> no longer exists upstream; checkout failing on a stale or locked .turbo-clone-temp directory.

Common situations: Slim Docker images and CI runners without git; firewalled environments that allow codeload HTTPS but block git; a leftover .turbo-clone-temp from a previously killed run.

Related errors


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