{"record":{"id":"5941827d5494e5fb","repo":"nexu-io/open-design","slug":"existing-config-at-where-is-not-valid-json-e","errorCode":null,"errorMessage":"existing config at ${where} is not valid JSON: ${err instanceof Error ? err.message : String(err)}","messagePattern":"existing config at (.+?) is not valid JSON: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/mcp-agent-install.ts","lineNumber":421,"sourceCode":"  for (const key of plan.keyPath) {\n    const next = cursor[key];\n    if (next == null || typeof next !== 'object' || Array.isArray(next)) {\n      return null;\n    }\n    cursor = next as Record<string, unknown>;\n  }\n  if (!(plan.serverKey in cursor)) return null;\n  delete cursor[plan.serverKey];\n  return `${JSON.stringify(root, null, 2)}\\n`;\n}\n\nfunction parseJsonObject(text: string | null, where: string): Record<string, unknown> {\n  if (text == null || text.trim() === '') return {};\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(text);\n  } catch (err) {\n    throw new Error(\n      `existing config at ${where} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n    );\n  }\n  if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new Error(`existing config at ${where} is not a JSON object`);\n  }\n  return parsed as Record<string, unknown>;\n}\n\n// --- Snippets for the manual (print-only) strategy ----------------------\n\nfunction genericMcpServersSnippet(spec: McpLaunchSpec, name: string): string {\n  const server: Record<string, unknown> = {\n    command: spec.command,\n    args: spec.args,\n  };\n  if (Object.keys(spec.env).length > 0) server.env = spec.env;\n  return JSON.stringify({ mcpServers: { [name]: server } }, null, 2);","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/mcp-agent-install.ts#L403-L439","documentation":"Thrown by parseJsonObject() in the MCP agent install pipeline when the existing target config file (e.g. claude_desktop_config.json, ~/.codex/config.json) exists but JSON.parse() throws a SyntaxError. The install pipeline refuses to overwrite a config it cannot parse, to avoid silently destroying a user's hand-maintained configuration. The error message includes the file path (`where`) and the underlying parse error.","triggerScenarios":"Running `od mcp install` (or any flow that calls applyJsonInstall/removeJsonInstall) against a target config file containing a JSON syntax error: trailing comma, unquoted key, single-quoted string, JSX/JSON5 comment (`//` or `/* */`), or a literal BOM/corruption.","commonSituations":"User has hand-edited their claude_desktop_config.json and left a trailing comma or comment; config was written by a tool that emits JSON5/JSONC; file was partially written and truncated; CRLF/encoding issues.","solutions":["Open the file at the path in the error message and fix the JSON syntax error (remove trailing commas, quote keys, remove comments).","Validate with `node -e 'JSON.parse(require(\"fs\").readFileSync(\"<path>\",\"utf8\"))'` or `jq . <path>`.","If the file is JSONC/JSON5, convert it to plain JSON before running the install.","Back up and regenerate the file from scratch if it is beyond quick repair."],"exampleFix":"// before (~/.config/claude/claude_desktop_config.json)\n{\n  \"mcpServers\": {\n    \"foo\": { \"command\": \"foo\" }, // trailing comma below\n  }\n}\n// after\n{\n  \"mcpServers\": {\n    \"foo\": { \"command\": \"foo\" }\n  }\n}","handlingStrategy":"validation","validationCode":"import { readFile } from 'node:fs/promises';\n\nasync function assertConfigParses(configPath: string): Promise<void> {\n  const text = await readFile(configPath, 'utf8').catch(() => null);\n  if (text == null || text.trim() === '') return;\n  try {\n    JSON.parse(text);\n  } catch (err) {\n    throw new Error(`Refusing to install: ${configPath} is not valid JSON (${(err as Error).message}). Fix or back up the file first.`);\n  }\n}\n\nawait assertConfigParses(plan.configPath);","typeGuard":null,"tryCatchPattern":"try {\n  applyJsonInstall(existingText, plan);\n} catch (error) {\n  if (error instanceof Error && error.message.includes('is not valid JSON')) {\n    // Prompt the user to fix the file at plan.configPath, then retry.\n    throw new Error(`MCP install aborted: fix JSON syntax in ${plan.configPath} first.`);\n  }\n  throw error;\n}","preventionTips":["Keep MCP client config files valid JSON (no comments, no trailing commas).","Validate with `jq . <file>` or `node -e 'JSON.parse(...)'` after hand-editing.","Back up config files before tools mutate them."],"tags":["mcp","agent-install","json","config","validation"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}