{"record":{"id":"b19cb379b99c1be4","repo":"affaan-m/ECC","slug":"invalid-label-at-filepath-expected-a-json-o-b19cb3","errorCode":null,"errorMessage":"Invalid ${label} at ${filePath}: expected a JSON object","messagePattern":"Invalid (.+?) at (.+?): expected a JSON object","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install-targets/kimi-project.js","lineNumber":19,"sourceCode":"const fs = require('fs');\nconst path = require('path');\n\nconst {\n  createInstallTargetAdapter,\n  createManagedOperation,\n  isForeignPlatformPath,\n} = require('./helpers');\n\nfunction readJsonObject(filePath, label) {\n  let parsed;\n  try {\n    parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n  } catch (error) {\n    throw new Error(`Failed to parse ${label} at ${filePath}: ${error.message}`);\n  }\n\n  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new Error(`Invalid ${label} at ${filePath}: expected a JSON object`);\n  }\n\n  return parsed;\n}\n\nfunction createMcpMergeOperation(moduleId, repoRoot, targetRoot) {\n  if (!repoRoot) {\n    throw new Error('repoRoot is required to plan Kimi MCP configuration');\n  }\n\n  const sourceRelativePath = '.mcp.json';\n  const sourcePath = path.join(repoRoot, sourceRelativePath);\n  if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isFile()) {\n    return null;\n  }\n\n  return createManagedOperation({\n    kind: 'merge-json',","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install-targets/kimi-project.js#L1-L37","documentation":"readJsonObject in the Kimi project target requires the parsed JSON root to be a plain object; null, arrays, and primitives are rejected because MCP merge needs an object to merge `mcpServers` into. The message includes the labeled file path so the offending file is easy to find.","triggerScenarios":"createMcpMergeOperation reads a Kimi project config file whose contents are valid JSON but whose top-level value is an array (e.g. `[]`), `null`, a string, or a number.","commonSituations":"A user initialized the Kimi MCP config as a JSON array of servers instead of an object; a template or script wrote `null` as a placeholder; an export tool produced a list-shaped config.","solutions":["Open the file at filePath and change the top-level value to a JSON object","If the file holds an array of servers, wrap it: `{ \"mcpServers\": { ... } }` mapping names to server objects","Replace `null`/`[]` placeholders with `{}` and re-run the install"],"exampleFix":"// before\n[ { \"name\": \"context7\", \"command\": \"npx\" } ]\n// after\n{ \"mcpServers\": { \"context7\": { \"command\": \"npx\" } } }","handlingStrategy":"type-guard","validationCode":"// Pre-check root shape of the Kimi MCP config\nconst parsed = JSON.parse(fs.readFileSync(kimiMcpPath, 'utf8'));\nif (parsed === null || Array.isArray(parsed) || typeof parsed !== 'object') {\n  console.error(`${kimiMcpPath} must be a JSON object at the top level`);\n}","typeGuard":"function isJsonObject(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  runInstallOperation(op);\n} catch (e) {\n  if (/Invalid .* at .*: expected a JSON object/.test(e.message)) {\n    // convert the file root to an object and re-run the install\n  } else throw e;\n}","preventionTips":["Structure MCP configs as `{ \"mcpServers\": { ... } }` objects, never arrays","Use `{}` for empty config files instead of `[]` or `null`","Validate parsed config root shape with a type guard before merge operations"],"tags":["json","type-mismatch","kimi","install-target"],"backgroundTag":"unexpected-response-shape","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}