paperclipai/paperclip · error · Error
Refusing to overwrite invalid config at ${filePath}: ${error
Error message
Refusing to overwrite invalid config at ${filePath}: ${error instanceof Error ? error.message : String(error)} What it means
Thrown by writeConfig() when an existing config file at the resolved path fails to parse/validate against paperclipConfigSchema during the merge-read step, AND the caller did not pass options.invalidBackupPath. The library refuses to silently overwrite a config it cannot understand, because doing so could destroy fields it does not recognize. The original parse error is embedded in the message.
Source
Thrown at cli/src/config/store.ts:206
configPath?: string,
options: { invalidBackupPath?: string } = {},
): boolean {
const filePath = resolveConfigPath(configPath);
const dir = path.dirname(filePath);
fs.mkdirSync(dir, { recursive: true });
let nextConfig = paperclipConfigSchema.parse(config);
if (fs.existsSync(filePath)) {
try {
const source = paperclipConfigSchema.parse(migrateLegacyConfig(parseJson(filePath)));
nextConfig = paperclipConfigSchema.parse(mergePaperclipConfig(source, nextConfig));
if (isDeepStrictEqual(effectiveConfig(source), effectiveConfig(nextConfig))) {
return false;
}
} catch (error) {
const invalidBackupPath = options.invalidBackupPath;
if (!invalidBackupPath) {
throw new Error(
`Refusing to overwrite invalid config at ${filePath}: ${error instanceof Error ? error.message : String(error)}`,
);
}
if (
!fs.existsSync(invalidBackupPath) ||
!fs.readFileSync(filePath).equals(fs.readFileSync(invalidBackupPath))
) {
throw new Error(
`Refusing to overwrite ${filePath} because it changed after the invalid backup was created`,
);
}
}
}
// Backup existing config before overwriting
if (fs.existsSync(filePath)) {
const backupPath = filePath + ".backup";
durableCopyFile(filePath, backupPath);View on GitHub (pinned to 67001ec6eb)
Solutions
- Pass options.invalidBackupPath pointing at a path returned by backupInvalidConfig() so the library can safely overwrite the bad config after verifying it matches the backup.
- Manually fix the existing config file until readConfig() succeeds, then retry writeConfig().
- Delete or move the corrupt config aside, then call writeConfig() to write a fresh one.
- Inspect the embedded parse error in the message to identify and correct the offending field.
Example fix
// before
writeConfig(newConfig, configPath); // throws if existing config is invalid
// after
import { backupInvalidConfig, writeConfig } from "./config/store.js";
const backup = backupInvalidConfig(configPath);
writeConfig(newConfig, configPath, { invalidBackupPath: backup }); Defensive patterns
Strategy: try-catch
Validate before calling
import { readConfig, backupInvalidConfig, writeConfig, configExists } from "./config/store.js";
function safeWriteConfig(nextConfig, configPath) {
if (!configExists(configPath)) return writeConfig(nextConfig, configPath);
try {
readConfig(configPath); // confirms existing config is valid
} catch {
const backup = backupInvalidConfig(configPath);
return writeConfig(nextConfig, configPath, { invalidBackupPath: backup });
}
return writeConfig(nextConfig, configPath);
} Type guard
import { paperclipConfigSchema } from "./schema.js";
import fs from "node:fs";
function existingConfigIsValid(filePath: string): boolean {
if (!fs.existsSync(filePath)) return true; // nothing to merge
try {
paperclipConfigSchema.parse(JSON.parse(fs.readFileSync(filePath, "utf-8")));
return true;
} catch { return false; }
} Try / catch
import { writeConfig, backupInvalidConfig } from "./config/store.js";
try {
writeConfig(cfg, configPath);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Refusing to overwrite invalid config")) {
const backup = backupInvalidConfig(configPath);
writeConfig(cfg, configPath, { invalidBackupPath: backup });
} else throw err;
} Prevention
- Always pass { invalidBackupPath } when calling writeConfig in automated flows that may encounter a corrupt existing config.
- Pre-validate the existing config with readConfig() before writing to detect corruption early.
- Surface the embedded parse error to the user so they can decide whether to overwrite.
When it happens
Trigger: Called writeConfig(config, configPath?, options) where the file exists but paperclipConfigSchema.parse(migrateLegacyConfig(parseJson(filePath))) throws (corrupt JSON, schema mismatch), and options.invalidBackupPath is undefined. The catch block checks for a backup path; without one it re-throws with this refusal message.
Common situations: 1) Existing config.json was hand-edited to an invalid state, then a programmatic writeConfig() call is made without the invalid-backup flow. 2) Version downgrade: a newer CLI wrote config fields the older schema rejects. 3) The config got corrupted by a partial write or merge tool.
Related errors
- Refusing to overwrite ${filePath} because it changed after t
- Failed to parse JSON at ${filePath}: ${err instanceof Error
- Company ID is required. Pass --company-id, set PAPERCLIP_COM
- Company ID is required. Pass --company-id, set PAPERCLIP_COM
- Company ID is required. Pass --company-id, set PAPERCLIP_COM
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/2b4baec0828fc9a0.
Report an issue: GitHub.