JuliusBrussee/caveman · error

${path} is not a JSON object

Error message

${path} is not a JSON object

What it means

parseJsonFileObject parses agent/config file bytes: empty or missing files yield {}, but if the parsed top-level value is not a JSON object (array, string, number, boolean, null) it throws with the file path. Note that syntactically invalid JSON surfaces as a JSON.parse SyntaxError before this check, not this message.

Source

Thrown at packages/cli/src/index.ts:5999

}

function atomicWriteFile(path: string, bytes: Buffer, mode = 0o600): void {
  mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
  const temp = join(dirname(path), `.${basename(path)}.caveman-${process.pid}-${randomUUID()}.tmp`);
  try {
    writeFileSync(temp, bytes, { mode });
    renameSync(temp, path);
    chmodSync(path, mode);
  } catch (error) {
    try { unlinkSync(temp); } catch { /* no partial */ }
    throw error;
  }
}

function parseJsonFileObject(path: string, bytes: Buffer | null): Record<string, unknown> {
  if (!bytes || bytes.length === 0) return {};
  const parsed = JSON.parse(bytes.toString("utf8"));
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${path} is not a JSON object`);
  return parsed as Record<string, unknown>;
}

function nativeMcpBinaryRequired(): string {
  const compatible = probeMcpBinary();
  if (!compatible) throw new Error("caveman-mcp not found; run `caveman setup --install`");
  if (!compatible.probe.current) throw new Error(`caveman-mcp ${compatible.probe.version} lacks current mcp_recovery capability; run \`caveman setup --install\``);
  return compatible.binary;
}

function nativeProxyBinaryRequired(gw: string): void {
  if (wrapMode(gw) !== "local") return;
  const binary = resolveGoBin("caveman-proxy", "CAVEMAN_PROXY_BIN");
  if (!binary) throw new Error("caveman-proxy not found; run `caveman setup --install`");
  const probe = probeVersionedBinary(binary, "native_runtime_v1");
  if (!probe.current) throw new Error(`caveman-proxy ${probe.version} lacks current native_runtime_v1 capability; run \`caveman setup --install\``);
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Open the named file and wrap its contents in an object: { "items": <existing array> } or restructure per the expected schema
  2. If the file is disposable config, delete it (empty/missing is tolerated as {}) and let caveman regenerate
  3. Validate with `jq -e 'type == "object"' <file>` before running setup

Example fix

// before (mcp.json)
[ { "name": "caveman-cloud" } ]

// after
{ "mcpServers": { "caveman-cloud": { } } }
Defensive patterns

Strategy: type-guard

Validate before calling

import { readFileSync } from "node:fs";
let parsed: unknown;
try { parsed = JSON.parse(readFileSync(path, "utf8")); }
catch { throw new Error(`${path} is not valid JSON`); }
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
  // safe: plain object
} else {
  throw new Error(`${path} top level is ${Array.isArray(parsed) ? "array" : typeof parsed}; expected object`);
}

Type guard

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

Try / catch

try {
  const root = parseJsonFileObject(path, bytes);
} catch (error) {
  if (/is not a JSON object/.test((error as Error).message)) {
    // schema issue in user-owned file: surface path and expected shape; never auto-overwrite
    reportConfigSchemaError(path);
  } else if (error instanceof SyntaxError) {
    reportConfigParseError(path);   // malformed JSON is a different failure
  } else throw error;
}

Prevention

When it happens

Trigger: Any config read path using parseJsonFileObject (agent settings, MCP config) where the file's top level is a JSON array like ["a","b"] or a bare scalar/string, or the literal "null".

Common situations: User hand-wrote a JSON array at top level; a different tool serialized a list into a config path; truncated writes producing valid scalar JSON is rare but arrays are the common case.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/c6220a998722ae1a. Report an issue: GitHub.