EveryInc/compound-engineering-plugin · warning
Warning: existing ${configPath} is not valid JSON. Writing p
Error message
Warning: existing ${configPath} is not valid JSON. Writing plugin config without merging. What it means
mergeOpenCodeConfig in src/targets/opencode.ts deep-merges incoming plugin configuration (MCP servers etc.) into the existing opencode.json. If the existing file cannot be parsed as JSON, the merge is abandoned with this warning and only the incoming config is written — the user's existing (invalid) config content is not merged, so any custom keys in it will be lost from the output.
Source
Thrown at src/targets/opencode.ts:57
}
if (!manifest?.groups[group]?.includes(entryName)) {
console.warn(`Skipping ${targetPath}: existing unmanaged file (not overwritten)`)
return true
}
return false
}
async function mergeOpenCodeConfig(
configPath: string,
incoming: OpenCodeConfig,
): Promise<OpenCodeConfig> {
if (!(await pathExists(configPath))) return incoming
let existing: OpenCodeConfig
try {
existing = await readJson<OpenCodeConfig>(configPath)
} catch {
console.warn(
`Warning: existing ${configPath} is not valid JSON. Writing plugin config without merging.`
)
return incoming
}
const mergedMcp = {
...(incoming.mcp ?? {}),
...(existing.mcp ?? {}),
}
const mergedPermission = incoming.permission
? {
...(incoming.permission),
...(existing.permission ?? {}),
}
: existing.permission
const mergedTools = incoming.toolsView on GitHub (pinned to c9c10f8c75)
Solutions
- Validate and repair the existing file: run it through `jq . opencode.json` or a JSON linter, fix the syntax error, then re-run the install so a proper merge occurs.
- If the file intentionally contains comments (JSONC), move comments out — opencode.json must be strict JSON for the merge to work.
- Back up the current file before re-running, since the next install will overwrite it with only the incoming plugin config.
- After repairing, re-run the install and confirm the warning no longer appears and your custom keys survived the merge.
Example fix
// before: opencode.json with comment/trailing comma
{ "mcp": { ... }, // my comment
}
// after: strict JSON
{
"mcp": { "...": "..." }
} Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'node:fs'
function assertStrictJson(filePath: string): void {
if (!existsSync(filePath)) return
JSON.parse(require('node:fs').readFileSync(filePath, 'utf8')) // throws on invalid/JSONC
}
assertStrictJson('opencode.json') // run before install Try / catch
try {
installOpenCode()
} catch (err) {
// merge warnings go to console.warn, not throw — check output
if (!jsonIsValid('opencode.json')) {
console.error('opencode.json is not strict JSON; fix it before reinstalling to avoid losing custom keys')
}
} Prevention
- Keep opencode.json strict JSON — no comments, trailing commas, or BOM
- Run `jq . opencode.json` (or a linter) as a pre-commit check after hand edits
- Keep custom config in a separate tracked copy so a bad merge is recoverable
When it happens
Trigger: readJson<OpenCodeConfig>(configPath) throws during an OpenCode bundle write because the existing configPath (opencode.json) contains malformed JSON — trailing commas, comments, BOM, truncated writes, or the file actually being JSONC.
Common situations: Users hand-editing opencode.json and introducing a syntax error; tools that write JSONC (comments allowed) into opencode.json; a crashed editor or partial write leaving a truncated file; copying a config.jsonc over opencode.json.
Related errors
- Could not read ${filePath}: ${error instanceof Error ? error
- ${label} returned invalid JSON: ${error instanceof Error ? e
- Skipping ${targetPath}: existing user-managed symlink (not o
- Skipping ${targetPath}: existing unmanaged file (not overwri
- Skipping agent "${agent.name}": sanitized name "${safeName}"
AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31).
Data as JSON: /api/errors/52399ce0b70f2e46.
Report an issue: GitHub.