vercel/turborepo · error · TransformError

Unable to update README.md

Error message

Unable to update README.md

What it means

The update-commands-in-readme transform rewrites package manager references in the new project's README.md. It first checks that README.md exists, then reads and writes the file. It throws this TransformError when the async read or write fails, for example a permission error, a dangling symlink, or a file locked by another process.

Solutions

  1. Re-run create-turbo in a fresh, fully writable directory
  2. If you maintain the example, replace the README.md symlink with a regular file
  3. Fix permissions on README.md and its parent directory before retrying
  4. Disable or exclude antivirus scanning for the creation directory, then retry
Defensive patterns

Strategy: validation

Validate before calling

import fs from "node:fs";

// ensure README.md is a regular, readable and writable file before transforms run
const st = fs.lstatSync(readmePath);
if (!st.isFile()) throw new Error("README.md must be a regular file");
fs.accessSync(readmePath, fs.constants.R_OK | fs.constants.W_OK);

Type guard

function isUsableReadme(p: string): boolean {
  try {
    const st = fs.lstatSync(p);
    return st.isFile() && fs.accessSync(p, fs.constants.R_OK | fs.constants.W_OK) === undefined;
  } catch {
    return false;
  }
}

Prevention

When it happens

Trigger: README.md exists but cannot be read or written. It is a symlink to a missing target, has no read or write permission, or is locked by another process. fs.readFile or fs.writeFile rejects and the catch converts it to this TransformError.

Common situations: A starter template ships README.md as a broken symlink. A read-only file inside the extracted example. Antivirus or an editor holding a lock on Windows during scaffolding.

Related errors


AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17). Data as JSON: /api/errors/b7803481374c0a45. Report an issue: GitHub.

Appendix: source

Thrown at packages/create-turbo/src/transforms/update-commands-in-readme.ts:53

  if (!prompts.packageManager) {
    return { result: "not-applicable", ...meta };
  }

  const readmeFilePath = path.join(prompts.root, "README.md");
  if (!fs.existsSync(readmeFilePath)) {
    return { result: "not-applicable", ...meta };
  }

  try {
    const data = await fs.readFile(readmeFilePath, "utf8");
    const updatedData = replacePackageManagerReferences(
      prompts.packageManager.name,
      data
    );
    await fs.writeFile(readmeFilePath, updatedData, "utf8");
  } catch (err) {
    throw new TransformError("Unable to update README.md", {
      transform: meta.name,
      fatal: false
    });
  }

  return { result: "success", ...meta };
}

/**
 * Within backtick-delimited code regions, replaces package manager references:
 * - "<pm> run" → "<selected> run"
 * - bare "<pm>" (not followed by "run") → "<selected>"
 */
export function replacePackageManagerReferences(
  targetPm: PackageManager,
  text: string
): string {
  return text.replace(CODE_REGION_REGEX, (codeBlock) => {

View on GitHub (pinned to f9245100cf)