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
- Open the named file and wrap its contents in an object: { "items": <existing array> } or restructure per the expected schema
- If the file is disposable config, delete it (empty/missing is tolerated as {}) and let caveman regenerate
- 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
- Top-level of agent config files must always be a JSON object
- Distinguish SyntaxError (invalid JSON) from this object-shape error when reporting
- Use `jq -e 'type == "object"' <file>` in CI checks on config files
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
- caveman build: invalid .caveman/provider.json
- ${settingsPath} env must be a JSON object; refusing to overw
- ${mcpPath} mcpServers must be a JSON object; refusing to ove
- ${settingsPath} mcpServers must be a JSON object; refusing t
- ${configPath} provider must be a JSON object; refusing to ov
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/c6220a998722ae1a.
Report an issue: GitHub.