nexu-io/open-design · error
project_files.read_json could not parse JSON at ${filePath}
Error message
project_files.read_json could not parse JSON at ${filePath} What it means
executeProjectFilesReadJson (refresh.ts:601-606) reads the file and calls JSON.parse on its UTF-8 contents; if parse throws (SyntaxError), the error is wrapped with the file path so the caller knows which file failed. The catch is broad, so any parse error surfaces here.
Source
Thrown at apps/daemon/src/live-artifacts/refresh.ts:605
const filePath = selectJsonPath(options.source.input as ProjectFilesReadJsonInput);
if (!filePath.endsWith('.json')) throw new Error('project_files.read_json only supports .json files');
const dir = projectDir(options.projectsRoot, options.projectId);
const target = path.resolve(dir, filePath);
const [dirReal, targetLinkStat] = await Promise.all([realpath(dir), lstat(target)]);
if (targetLinkStat.isSymbolicLink()) throw new Error('project_files.read_json does not follow symlinks');
const targetReal = await realpath(target);
if (!targetReal.startsWith(`${dirReal}${path.sep}`) && targetReal !== dirReal) {
throw new Error('project_files.read_json path escapes project dir');
}
const entryStat = await stat(targetReal);
if (!entryStat.isFile()) throw new Error('project_files.read_json path must be a file');
if (entryStat.size > 256 * 1024) throw new Error('project_files.read_json file exceeds 256KB');
if (options.signal?.aborted === true) throw options.signal.reason;
let parsed: BoundedJsonValue;
try {
parsed = JSON.parse(await readFile(targetReal, 'utf8')) as BoundedJsonValue;
} catch {
throw new Error(`project_files.read_json could not parse JSON at ${filePath}`);
}
return asBoundedRefreshOutput({ toolName: 'project_files.read_json', path: filePath, size: entryStat.size, json: parsed });
}
function compactExecOutput(value: string): string[] {
return value.split('\n').map((line) => line.trimEnd()).filter(Boolean).slice(0, 100);
}
async function runGit(projectPath: string, args: string[], signal: AbortSignal | undefined): Promise<string> {
try {
const result = await execFileAsync('git', args, { cwd: projectPath, signal, timeout: 10_000, maxBuffer: 128 * 1024 });
return result.stdout.toString();
} catch (error) {
const maybeError = error as { stdout?: string | Buffer; stderr?: string | Buffer; message?: string; code?: unknown };
if (maybeError.code === 128) return '';
throw new Error(maybeError.stderr?.toString().trim() || maybeError.message || 'git command failed');
}
}View on GitHub (pinned to 5be4028344)
Solutions
- Validate the file with a JSON linter (e.g. `node -e "JSON.parse(require('fs').readFileSync('f','utf8'))"`) and fix the syntax error.
- Remove comments, trailing commas, and single quotes; use strict JSON.
- If you need JSONC/JSON5, convert to plain JSON before pointing read_json at it.
Example fix
// before: data.json contains
// {
// "total": 1, // the count
// "items": [],
// }
// throws `project_files.read_json could not parse JSON at data.json`
// after: valid JSON (no comments, no trailing comma)
// { "total": 1, "items": [] } Defensive patterns
Strategy: validation
Validate before calling
import { readFile } from 'node:fs/promises';
async function assertValidJson(target: string): Promise<void> {
try {
JSON.parse(await readFile(target, 'utf8')) as unknown;
} catch {
throw new Error(`project_files.read_json could not parse JSON at ${target}`);
}
} Try / catch
try {
await refreshLiveArtifact(opts);
} catch (err) {
if (err instanceof Error && err.message.startsWith('project_files.read_json could not parse JSON')) {
// prompt the user to fix the file's JSON syntax
}
throw err;
} Prevention
- Lint JSON files before committing (e.g. `node --check` or a JSON validator).
- Avoid comments, trailing commas, and single quotes in files read by read_json.
- Convert JSONC/JSON5/YAML to strict JSON before pointing read_json at them.
When it happens
Trigger: The target .json file exists, is under 256 KiB, is inside the project, but its contents are not valid JSON (e.g. trailing comma, single quotes, comments, JSONC/JSON5 syntax, BOM + corrupted bytes, truncated file).
Common situations: JSON-with-comments files (.jsonc) read as strict JSON; hand-edited JSON with a trailing comma; a truncated/corrupted file from an interrupted write; a file that is actually JSON5 or YAML.
Related errors
- project_files.read_json requires input.path
- project_files.read_json only supports .json files
- project_files.read_json does not follow symlinks
- project_files.read_json path escapes project dir
- project_files.read_json path must be a file
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/f2808468d5b249f2.
Report an issue: GitHub.