ruvnet/ruflo · error · Error

Import file must contain a JSON object

Error message

Import file must contain a JSON object

What it means

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.

Source

Thrown at v3/@claude-flow/cli/src/services/config-file-manager.ts:164

    const resolved = path.resolve(cwd, exportPath);
    this.writeAtomic(resolved, config);
  }

  /** Import config from a specific path */
  importFrom(cwd: string, importPath: string): void {
    const resolved = path.resolve(cwd, importPath);
    if (!fs.existsSync(resolved)) {
      throw new Error(`Import file not found: ${resolved}`);
    }
    const content = fs.readFileSync(resolved, 'utf-8');
    let imported: Record<string, unknown>;
    try {
      imported = JSON.parse(content);
    } catch {
      throw new Error(`Invalid JSON in import file: ${resolved}`);
    }
    if (typeof imported !== 'object' || imported === null || Array.isArray(imported)) {
      throw new Error('Import file must contain a JSON object');
    }
    const targetPath = this.configPath ?? path.resolve(cwd, CONFIG_FILENAMES[0]);
    this.writeAtomic(targetPath, imported);
    this.config = imported;
    this.configPath = targetPath;
  }

  /** Get the path to the current config file */
  getConfigPath(): string | null {
    return this.configPath;
  }

  /** Get default config */
  getDefaults(): Record<string, unknown> {
    return { ...DEFAULT_CONFIG };
  }

  /** Atomic write: write to .tmp then rename */

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Shape-check before importing: Array.isArray(parsed) || parsed === null || typeof parsed !== 'object'.
  2. Re-export from a working project so the file has an object root like {"version":...,"agents":...}.
  3. If you genuinely have an array, pick one element and write it as the single root object.

Example fix

// before — file contents: [ { "version": "3.5" } ]
manager.importFrom(cwd, './config.json'); // throws 'must contain a JSON object'

// after — file contents: { "version": "3.5", "agents": { ... } }
manager.importFrom(cwd, './config.json'); // ok
Defensive patterns

Strategy: validation

Validate before calling

const raw = fs.readFileSync(path.resolve(cwd, importPath), 'utf-8');
const parsed = JSON.parse(raw);
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
  throw new Error('import root must be a JSON object');
}
manager.importFrom(cwd, importPath);

Type guard

function isJsonObject(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/2de571016fb6f1aa. Report an issue: GitHub.