vercel-labs/agent-skills · error · Error
Could not read ${label} JSON at ${path}: ${err.message}
Error message
Could not read ${label} JSON at ${path}: ${err.message} What it means
Thrown by readJson() when either readFile or JSON.parse throws for the given path/label. It wraps the underlying error message, so the detail reveals whether the file was missing (ENOENT), unreadable (permissions), or present but not valid JSON (SyntaxError). This is the single chokepoint for loading both signals.json and codebase.json.
Source
Thrown at skills/vercel-optimize/scripts/merge-signals.mjs:160
function parseArgs(argv) {
const out = { positional: [], force: false };
for (let i = 0; i < argv.length; i++) {
const a = argv[i];
if (a === '--out') out.outPath = argv[++i];
else if (a.startsWith('--out=')) out.outPath = a.slice('--out='.length);
else if (a === '--force') out.force = true;
else out.positional.push(a);
}
out.signalsPath = out.positional[0];
out.codebasePath = out.positional[1];
return out;
}
async function readJson(path, label) {
try {
return JSON.parse(await readFile(path, 'utf-8'));
} catch (err) {
throw new Error(`Could not read ${label} JSON at ${path}: ${err.message}`);
}
}
function assertObject(value, label) {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`${label} must be a JSON object.`);
}
}
async function writeOutput(path, body, { force }) {
if (!force && await exists(path)) {
throw new Error(`output file already exists: ${path}. Use a fresh run directory or pass --force to overwrite.`);
}
await mkdir(dirname(path), { recursive: true });
await writeFile(path, body);
}
async function exists(path) {View on GitHub (pinned to b8caa260a4)
Solutions
- Confirm the path exists and is readable: `ls -l <path>` and `node -e 'JSON.parse(require("fs").readFileSync("<path>","utf8"))'`.
- If the file is truncated/malformed, rerun the step that produced it (collect-signals or scan-codebase).
- Run merge-signals from the directory containing the outputs, or pass absolute paths.
Example fix
// before — readJson surfaces an opaque wrapped error
throw new Error(`Could not read ${label} JSON at ${path}: ${err.message}`);
// after — validate existence + parseability with a clear precondition
import { readFileSync, existsSync } from 'node:fs';
function assertReadableJson(path, label) {
if (!existsSync(path)) throw new Error(`${label} not found at ${path}`);
try { JSON.parse(readFileSync(path, 'utf-8')); }
catch (e) { throw new Error(`${label} at ${path} is not valid JSON: ${e.message}`); }
} Defensive patterns
Strategy: try-catch
Validate before calling
import { existsSync } from 'node:fs';
import { readFileSync } from 'node:fs';
function assertJsonReadable(path, label) {
if (!existsSync(path)) throw new Error(`${label} not found at ${path}`);
try { JSON.parse(readFileSync(path, 'utf-8')); }
catch (e) { throw new Error(`${label} at ${path} is not valid JSON: ${e.message}`); }
}
assertJsonReadable(signalsPath, 'signals'); Try / catch
let parsed;
try {
parsed = await readJson(path, label);
} catch (err) {
if (err.message.startsWith(`Could not read ${label}`)) {
// distinguish missing vs malformed from err.message, then rerun producer or fix path
throw new Error(`Cannot load ${label}; fix the path or regenerate the file.`);
}
throw err;
} Prevention
- Run merge-signals from the directory containing the outputs, or use absolute paths.
- Regenerate truncated/partial JSON by rerunning collect-signals/scan-codebase.
- Assert files exist and parse before invoking merge.
When it happens
Trigger: The signals or codebase path does not exist (typo, wrong working directory); the file exists but contains malformed JSON (truncated write, trailing comma, BOM); permission denied on the file.
Common situations: Running merge-signals from a different cwd than where outputs were written; a previous collect/scan step crashed mid-write leaving a partial JSON file; path constructed with a wrong variable.
Related errors
- output file already exists: ${path}. Use a fresh run directo
- output file already exists: ${outPath}. Use a fresh run dire
- VERCEL_VERSION_UNPARSEABLE
- ${label} must be a JSON object.
- VERCEL_NOT_INSTALLED
AI-assisted analysis of vercel-labs/agent-skills@b8caa260a4 (2026-08-13).
Data as JSON: /api/errors/d7a512f0bde721b5.
Report an issue: GitHub.