{"record":{"id":"2de571016fb6f1aa","repo":"ruvnet/ruflo","slug":"import-file-must-contain-a-json-object","errorCode":null,"errorMessage":"Import file must contain a JSON object","messagePattern":"Import file must contain a JSON object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/config-file-manager.ts","lineNumber":164,"sourceCode":"    const resolved = path.resolve(cwd, exportPath);\n    this.writeAtomic(resolved, config);\n  }\n\n  /** Import config from a specific path */\n  importFrom(cwd: string, importPath: string): void {\n    const resolved = path.resolve(cwd, importPath);\n    if (!fs.existsSync(resolved)) {\n      throw new Error(`Import file not found: ${resolved}`);\n    }\n    const content = fs.readFileSync(resolved, 'utf-8');\n    let imported: Record<string, unknown>;\n    try {\n      imported = JSON.parse(content);\n    } catch {\n      throw new Error(`Invalid JSON in import file: ${resolved}`);\n    }\n    if (typeof imported !== 'object' || imported === null || Array.isArray(imported)) {\n      throw new Error('Import file must contain a JSON object');\n    }\n    const targetPath = this.configPath ?? path.resolve(cwd, CONFIG_FILENAMES[0]);\n    this.writeAtomic(targetPath, imported);\n    this.config = imported;\n    this.configPath = targetPath;\n  }\n\n  /** Get the path to the current config file */\n  getConfigPath(): string | null {\n    return this.configPath;\n  }\n\n  /** Get default config */\n  getDefaults(): Record<string, unknown> {\n    return { ...DEFAULT_CONFIG };\n  }\n\n  /** Atomic write: write to .tmp then rename */","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/services/config-file-manager.ts#L146-L182","documentation":"ConfigFileManager.importFrom succeeds in JSON.parse but then checks the parsed value is a plain object (typeof === 'object', not null, not an array). A config file must be a JSON object at the top level; arrays, primitives, or null are rejected because setNestedValue and the rest of the manager assume an object root.","triggerScenarios":"The import file parses to a JSON array (e.g. [...] ), to null, or to a primitive (a bare string/number/boolean). The file is valid JSON but the wrong shape.","commonSituations":"Exporting a list of configs instead of one object; the file contains just a quoted string; a templating tool rendered an array wrapper; someone replaced the config object with null.","solutions":["Shape-check before importing: Array.isArray(parsed) || parsed === null || typeof parsed !== 'object'.","Re-export from a working project so the file has an object root like {\"version\":...,\"agents\":...}.","If you genuinely have an array, pick one element and write it as the single root object."],"exampleFix":"// before — file contents: [ { \"version\": \"3.5\" } ]\nmanager.importFrom(cwd, './config.json'); // throws 'must contain a JSON object'\n\n// after — file contents: { \"version\": \"3.5\", \"agents\": { ... } }\nmanager.importFrom(cwd, './config.json'); // ok","handlingStrategy":"validation","validationCode":"const raw = fs.readFileSync(path.resolve(cwd, importPath), 'utf-8');\nconst parsed = JSON.parse(raw);\nif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n  throw new Error('import root must be a JSON object');\n}\nmanager.importFrom(cwd, importPath);","typeGuard":"function isJsonObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Ensure exported configs always have an object root.","When templating configs, wrap the output in an object, not an array.","Shape-check parsed imports before relying on them.","Use isJsonObject() to narrow before setNestedValue-style access."],"tags":["config","json","validation","typescript"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}