shadcn-ui/ui · error · FileBackupError
Could not back up ${filePath}.
Error message
Could not back up ${filePath}. What it means
Thrown as a FileBackupError when createFileBackup cannot rename a linked workspace's components.json to its .bak sidecar during `shadcn apply`. The apply command backs up every linked workspace config before writing the style/tailwind patch; if the atomic rename inside createFileBackup throws, it returns null and the sync aborts with this error.
Source
Thrown at packages/shadcn/src/commands/apply.ts:486
const configPath = path.resolve(
linkedConfig.resolvedPaths.cwd,
"components.json"
)
if (!(await fs.pathExists(configPath))) {
continue
}
workspaceConfigs.push({
configPath,
existingConfig: await fs.readJson(configPath),
})
}
try {
for (const workspaceConfig of workspaceConfigs) {
const backupPath = createFileBackup(workspaceConfig.configPath)
if (!backupPath) {
throw new FileBackupError(workspaceConfig.configPath)
}
}
for (const workspaceConfig of workspaceConfigs) {
await fs.writeJson(
workspaceConfig.configPath,
{
...workspaceConfig.existingConfig,
...patch,
tailwind: {
...workspaceConfig.existingConfig.tailwind,
...patch.tailwind,
},
},
{ spaces: 2 }
)
}
View on GitHub (pinned to efac598707)
Solutions
- Verify write permissions on each linked workspace's components.json AND its parent directory (chmod/chown).
- Ensure the working directory and the target config are on the same filesystem (avoid separate /tmp mounts).
- Remove any stale components.json.bak files left by a previous crashed run before retrying.
- Disable file-locking antivirus / pause IDE watchers for the project directory and retry.
- Re-run with adequate privileges and a writable working tree (not a read-only container filesystem).
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight before calling the apply sync path: ensure each linked
// workspace's components.json is on a writable directory.
import fs from "fs-extra"
import path from "path"
async function assertBackupCapable(configPaths: string[]) {
for (const p of configPaths) {
const dir = path.dirname(p)
try {
await fs.access(dir, fs.constants.W_OK | fs.constants.R_OK)
} catch {
throw new Error(`Directory not writable for backup: ${dir}`)
}
// Stale .bak from a prior crashed run will block rename on some FSes.
const bak = `${p}.bak`
if (await fs.pathExists(bak)) await fs.remove(bak)
}
} Type guard
import fs from "fs-extra"
import path from "path"
function isBackupCapableSync(filePath: string): boolean {
try {
fs.accessSync(path.dirname(filePath), fs.constants.W_OK | fs.constants.R_OK)
return true
} catch {
return false
}
} Try / catch
try {
await applyWorkspaceSync(config)
} catch (e) {
if (e instanceof Error && /Could not back up/.test(e.message)) {
// e.filePath (FileBackupError) holds the offending config path.
const offending = (e as { filePath?: string }).filePath
console.error(`Backup failed for ${offending}. Check permissions / clean .bak files.`)
}
throw e
} Prevention
- Run shadcn apply from a writable working tree, not a read-only mount.
- Ensure all linked workspaces live on the same volume as the project root.
- Clean up components.json.bak files before re-running apply.
When it happens
Trigger: Running `shadcn apply` in a monorepo where getWorkspaceConfig yields linked configs, and createFileBackup returns null for one of them. The existence of components.json is already verified at apply.ts:472, so null here means fsExtra.renameSync threw — EPERM/EACCES, EXDEV (cross-device rename), or the file vanished between the exists-check and the rename.
Common situations: Read-only filesystem (CI runner, container with read-only mount), permission denied on components.json or its parent dir, /tmp or workspace on a different mount than the project (EXDEV), a stale .bak held open by another process, antivirus/file-locking on Windows, IDE watcher holding the file.
Related errors
- Failed to sync linked workspace configs. ${error.message}
- Could not back up ${filePath}.
- Failed to read config at ${options.cwd}.
- Missing value for --only. Use one or more of: ${APPLY_ONLY_V
- Invalid value for --only: ${value}. Use one or more of: ${AP
AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12).
Data as JSON: /api/errors/7ba0916f3394b861.
Report an issue: GitHub.