affaan-m/ECC · error
Unable to update Claude settings at
Error message
Unable to update Claude settings at ${settingsPath} What it means
update() retries a read-modify-write cycle against the Claude settings file, detecting concurrent modifications via the ECC_SETTINGS_CHANGED sentinel. If the retry loop is exhausted (or fails for a non-ECC_SETTINGS_CHANGED reason it rethrows immediately), it throws this error indicating the settings file could not be updated at the given path. It is a deliberate failure rather than a silent partial write.
Solutions
- Rerun the operation once no other install/update process is running; transient races resolve on retry.
- Identify concurrent writers (another terminal running the installer, CI job, file-sync daemon) and stop them before updating.
- Exclude ~/.claude/settings.json from cloud-sync/watcher tools that rewrite it during operations.
- Check the `cause`/original error if a non-ECC_SETTINGS_CHANGED error surfaced and fix that root problem first.
Defensive patterns
Strategy: retry
Try / catch
try {
await updateSettingsAtomic(path, fn);
} catch (error) {
if (error.message.startsWith('Unable to update Claude settings')) {
await new Promise(r => setTimeout(r, 250));
await updateSettingsAtomic(path, fn); // single manual retry after quiescing writers
} else throw error;
} Prevention
- Don't run two installer processes against the same ~/.claude simultaneously
- Exclude settings.json from file-sync tools (Dropbox/OneDrive) on dev machines
- Serialize install operations in CI with a lock or single job
- Inspect error.cause when the failure is not a settings-changed race
When it happens
Trigger: Calling updateSettingsAtomic(path, fn) while another process repeatedly rewrites the settings file so every attempt sees ECC_SETTINGS_CHANGED, exhausting maxAttempts; or the underlying update function throwing a non-retryable error.
Common situations: Two installs/updates racing on the same machine (CI plus a local dev server), a file watcher or sync tool (Dropbox/OneDrive) constantly touching settings.json, or an unrelated thrown error inside the update callback being mistaken for a lock problem.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Another ECC process is updating Claude settings
- Another Nasiko lifecycle operation is already in progress…
- Another Nasiko lifecycle operation won lock acquisition
- Another Nasiko lifecycle operation won stale-lock recovery
- atomic promotion compare-and-swap failed
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/8233cb72be87227a.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/claude-settings.js:441
settingsPath,
`${JSON.stringify(result.settings, null, 2)}\n`,
{
encoding: 'utf8',
mode: snapshot.mode,
validateParent,
beforeRename() {
assertSettingsSnapshotUnchanged(settingsPath, snapshot);
},
}
);
return result;
} catch (error) {
if (error.code !== 'ECC_SETTINGS_CHANGED' || attempt === maxAttempts) {
throw error;
}
}
}
throw new Error(`Unable to update Claude settings at ${settingsPath}`);
};
if (options.lockHeld) {
return update();
}
return runWithSettingsLock(settingsPath, update);
}
function reference(event, id) {
return { event, id };
}
function entriesMatchingId(entries, id) {
return entries
.map((entry, index) => ({ entry, index }))
.filter(candidate => isJsonObject(candidate.entry) && candidate.entry.id === id);
}
function assertUnambiguousMatch(entries, event, id) {View on GitHub (pinned to 8321021c54)