nexu-io/open-design · error
project_files.read_json only supports .json files
Error message
project_files.read_json only supports .json files
What it means
executeProjectFilesReadJson (refresh.ts:587-588) requires the resolved file path to end with '.json'. This bounds the tool to JSON parsing only (it immediately JSON.parse's the contents), so non-JSON files are rejected before any filesystem traversal.
Source
Thrown at apps/daemon/src/live-artifacts/refresh.ts:588
if (!matched) continue;
const result: BoundedJsonObject = {
path: file.path,
name: file.name,
size: file.size,
mtime: file.mtime,
kind: file.kind ?? 'file',
mime: file.mime ?? 'application/octet-stream',
};
if (preview !== undefined) result.preview = preview;
matches.push(result);
}
return asBoundedRefreshOutput({ toolName: 'project_files.search', query: query ?? '', count: matches.length, truncated: allFiles.length > matches.length && matches.length >= maxResults, matches });
}
async function executeProjectFilesReadJson(options: ExecuteLocalDaemonRefreshSourceOptions): Promise<BoundedJsonObject> {
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}`);
}View on GitHub (pinned to 5be4028344)
Solutions
- Use a '.json' file path (lowercase).
- If your data is JSONC/JSON5/YAML, convert it to plain JSON first, or use a different source type.
- Rename or copy the file with a .json extension if its contents are valid JSON.
Example fix
// before
const input = { path: 'config.yaml' };
// throws `project_files.read_json only supports .json files`
// after
const input = { path: 'config.json' }; Defensive patterns
Strategy: validation
Validate before calling
function assertJsonFilePath(p: string): void {
if (!p.toLowerCase().endsWith('.json')) {
throw new Error('project_files.read_json only supports .json files');
}
} Type guard
function isJsonFilePath(p: unknown): p is string {
return typeof p === 'string' && p.toLowerCase().endsWith('.json');
} Prevention
- Restrict the path picker UI to .json files for read_json sources.
- Reject non-.json extensions at the input boundary with a clear message.
- For JSONC/JSON5, convert to plain JSON before exposing to read_json.
When it happens
Trigger: input.path (or file/name) resolves to a path whose final extension is not '.json', e.g. 'data.txt', 'config.yaml', 'package.jsonc'.
Common situations: Pointing the read_json tool at a JSONC/YAML/TXT file by mistake; a path with no extension; a case-sensitivity issue such as '.JSON' (the check is case-sensitive on lowercased extension only via endsWith).
Related errors
- project_files.read_json requires input.path
- 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
- project_files.read_json file exceeds 256KB
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/5f1afd3e69bb2ec3.
Report an issue: GitHub.