affaan-m/ECC · error · Error
Refusing to overwrite unowned JSON fields at
Error message
Refusing to overwrite unowned JSON fields at ${destinationPath}: ${conflicts.join(', ')} What it means
For a merge-json operation whose destination is not yet an ECC-owned destination, findJsonConflicts compares the existing JSON with the merge payload. If any existing key (recursively) would be changed to a different value, classifyManagedOperation throws this error listing the conflicting field paths. ECC refuses to silently overwrite user-set values in files it does not own.
Solutions
- Review the listed conflicting fields and manually align them with ECC's intended values, or set your own values after install.
- Back up the file, let the install claim it (establishing ownership via the guided flow), then reapply your customizations.
- Regenerate install-state (delete state file, re-run guided install) so existing files become owned destinations instead of unowned conflicts.
- Split your custom config into a separate file/key that ECC's merge payload does not touch.
Example fix
// before: user changed mcpServers.context7.url in an unowned config
// after: remove/rename your custom key so the merge applies cleanly
{ "mcpServers": { "context7": { "url": "https://default.example" } }, "myCustomOverrides": { "url": "https://mine.example" } } Defensive patterns
Strategy: try-catch
Validate before calling
const existing = JSON.parse(fs.readFileSync(destinationPath, 'utf8'));
const conflicts = findJsonConflicts(existing, operation.mergePayload); // same recursive diff the lib uses
if (conflicts.length) console.warn('Conflicting keys to resolve before install:', conflicts); Try / catch
try {
await runInstall(plan);
} catch (err) {
if (String(err.message).startsWith('Refusing to overwrite unowned JSON fields')) {
const fields = err.message.split(': ')[1];
console.error(`Resolve these keys manually or back up the file: ${fields}`);
} else throw err;
} Prevention
- Diff your config against ECC's intended merge payload before installing.
- Keep personal overrides in separate keys/files the merge payload never touches.
- Back up config files before running installs into an existing repo.
- Re-run the guided install rather than hand-editing managed configs so ownership stays consistent.
When it happens
Trigger: Running an install/update where a merge-json destination exists, is absent from the owned-destinations set (no trusted install-state coverage), and at least one key in operation.mergePayload has a different existing value — e.g. user edited a shared config key ECC also wants to set.
Common situations: User customized a key in .mcp.json or a harness config that a new ECC module also writes; installing ECC into a repo where another tool set the same config keys; re-installing after manually editing managed config without refreshing ownership state.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- candidate configuration exceeds 1 MiB
- Cannot merge ECC configuration at
- Cannot merge ECC configuration into invalid JSON at
- Failed to load policy from
- Failed to parse
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/79422f93b2aa5a6a.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/multi-harness-setup.js:279
const field = prefix ? `${prefix}.${key}` : key;
if (isPlainObject(currentValue) && isPlainObject(patchValue)) {
return findJsonConflicts(currentValue, patchValue, field);
}
return JSON.stringify(currentValue) === JSON.stringify(patchValue) ? [] : [field];
});
}
function classifyManagedOperation(operation, ownedDestinations) {
const destinationPath = operation.destinationPath;
const destination = readRegularFileSnapshot(destinationPath);
if (!destination) return 'create';
const canonicalDestination = canonicalPath(destinationPath);
if (operation.kind === 'merge-json') {
const current = assertMergeDestination(destinationPath, destination);
if (ownedDestinations.has(canonicalDestination)) return 'managed-json-update';
const conflicts = findJsonConflicts(current, operation.mergePayload);
if (conflicts.length > 0) {
throw new Error(
`Refusing to overwrite unowned JSON fields at ${destinationPath}: ${conflicts.join(', ')}`
);
}
return 'json-merge';
}
if (ownedDestinations.has(canonicalDestination)) return 'managed-update';
if (
operation.kind === 'copy-file'
&& typeof operation.sourcePath === 'string'
&& readRegularFileSnapshot(operation.sourcePath)?.content.equals(destination.content)
) {
return 'identical';
}
throw new Error(`Refusing to replace unowned existing file: ${destinationPath}`);
}
function writableRequirement(destinationPath) {
if (fs.existsSync(destinationPath)) {View on GitHub (pinned to 8321021c54)