shadcn-ui/ui · error · FileBackupError

Could not back up ${filePath}.

Error message

Could not back up ${filePath}.

What it means

Thrown as FileBackupError by withFileBackup when createFileBackup returns null. createFileBackup tries fsExtra.renameSync(filePath, filePath + '.bak'); if the rename throws (caught and returned as null), withFileBackup aborts rather than risk modifying a file it cannot restore. The error name is "FileBackupError" and the filePath is attached.

Source

Thrown at packages/shadcn/src/utils/file-helper.ts:74

    return true
  } catch {
    // Best effort - don't log as this is just cleanup
    return false
  }
}

export async function withFileBackup<T>(
  filePath: string,
  task: () => Promise<T>
) {
  if (!fsExtra.existsSync(filePath)) {
    return task()
  }

  const backupPath = createFileBackup(filePath)

  if (!backupPath) {
    throw new FileBackupError(filePath)
  }

  const restoreBackupOnExit = () => restoreFileBackup(filePath)

  process.on("exit", restoreBackupOnExit)

  try {
    const result = await task()
    process.removeListener("exit", restoreBackupOnExit)
    deleteFileBackup(filePath)
    return result
  } catch (error) {
    process.removeListener("exit", restoreBackupOnExit)
    restoreFileBackup(filePath)
    throw error
  }
}

View on GitHub (pinned to efac598707)

Solutions

  1. Check write permissions on the file and its directory; chmod or chown as needed.
  2. Remove any stale <file>.bak left from a previous failed run.
  3. Ensure the file and its .bak target are on the same filesystem/device (rename does not cross devices).
  4. Close any program holding an exclusive lock on the file, then retry.

Example fix

# before — stale .bak or permission issue
ls -la components.json components.json.bak
# after
rm -f components.json.bak
chmod u+w components.json
# then re-run the shadcn command
Defensive patterns

Strategy: try-catch

Validate before calling

import fsExtra from "fs-extra"
function canBackup(filePath: string): boolean {
  if (!fsExtra.existsSync(filePath)) return true // nothing to back up
  try {
    fsExtra.accessSync(filePath, fsExtra.constants.W_OK)
    fsExtra.accessSync(path.dirname(filePath), fsExtra.constants.W_OK)
    return !fsExtra.existsSync(`${filePath}.bak`)
  } catch {
    return false
  }
}

Type guard

const isBackupable = (filePath: string) => canBackup(filePath)

Try / catch

try {
  await withFileBackup(filePath, task)
} catch (e) {
  if (e.name === "FileBackupError") {
    // fix permissions / remove stale .bak, then retry
  }
  throw e
}

Prevention

When it happens

Trigger: withFileBackup(filePath, task) is called for a file that exists; createFileBackup attempts to rename it to a .bak sibling; renameSync fails (e.g. cross-device link, permission denied, read-only filesystem, file locked by another process, .bak already exists and target is busy).

Common situations: Project on a read-only mount or a filesystem that rejects rename; permission issues on the file or its directory; an existing .bak left over from a crashed run that cannot be overwritten; antivirus/process locking the file on Windows.

Related errors


AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12). Data as JSON: /api/errors/2892c058dad242c5. Report an issue: GitHub.