can1357/oh-my-pi · error · Error

Invalid package.json at ${absolutePath}: ${err}

Error message

Invalid package.json at ${absolutePath}: ${err}

What it means

linkPlugin reads the target package.json with pkgFile.json(). If the file cannot be parsed as JSON the error is rethrown with the path and the original parse error. This wraps JSON syntax errors so the user knows which manifest is broken.

Source

Thrown at packages/coding-agent/src/extensibility/plugins/installer.ts:163

	// Validate that resolved path is within cwd to prevent path traversal
	const normalizedCwd = path.resolve(cwd);
	const normalizedPath = path.resolve(absolutePath);
	if (!normalizedPath.startsWith(`${normalizedCwd}/`) && normalizedPath !== normalizedCwd) {
		throw new Error(`Invalid path: ${localPath} resolves outside working directory`);
	}

	// Validate package.json exists
	const pkgFile = Bun.file(path.join(absolutePath, "package.json"));
	if (!(await pkgFile.exists())) {
		throw new Error(`package.json not found at ${absolutePath}`);
	}

	let pkg: { name?: string };
	try {
		pkg = await pkgFile.json();
	} catch (err) {
		throw new Error(`Invalid package.json at ${absolutePath}: ${err}`);
	}

	if (!pkg.name || typeof pkg.name !== "string") {
		throw new Error("package.json must have a valid name field");
	}

	// Validate package name to prevent path traversal via pkg.name
	if (pkg.name.includes("..") || pkg.name.includes("/") || pkg.name.includes("\\")) {
		// Exception: scoped packages have one slash
		if (!pkg.name.startsWith("@") || (pkg.name.match(/\//g) || []).length !== 1) {
			throw new Error(`Invalid package name in package.json: ${pkg.name}`);
		}
	}

	await ensurePluginsDir();

	// Create symlink in plugins/node_modules
	const linkPath = path.join(PLUGINS_DIR, "node_modules", pkg.name);

View on GitHub (pinned to 9690622007)

Solutions

  1. Validate the package.json with `node -e "JSON.parse(require('fs').readFileSync('<path>/package.json'))"` or a JSON linter
  2. Fix the reported JSON syntax error (remove trailing commas/comments, fix truncation)
  3. Re-save the file as strict UTF-8 without BOM
  4. Re-run linkPlugin once the file parses

Example fix

// before: package.json with comment
{
	"name": "my-plugin", // not valid JSON
}
// after
{
	"name": "my-plugin"
}
Defensive patterns

Strategy: validation

Validate before calling

const raw = await Bun.file(path.join(dir, "package.json")).text();
JSON.parse(raw); // throws with position info before calling linkPlugin

Try / catch

try {
	await linkPlugin(dir);
} catch (err) {
	if (err instanceof Error && err.message.startsWith("Invalid package.json")) {
		console.error("Fix JSON syntax in", err.message.split(" at ")[1]);
	}
	throw err;
}

Prevention

When it happens

Trigger: linkPlugin(localPath, cwd) targets a directory whose package.json contains invalid JSON: trailing commas, comments (JSONC), BOM, truncated writes, or non-UTF8 encoding.

Common situations: Hand-edited package.json left syntactically invalid; tooling wrote JSONC (comments) which JSON.parse rejects; file partially written during a crash; editor autosave race while the link was attempted.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/8c6aa38a6b4054d5. Report an issue: GitHub.