can1357/oh-my-pi · error · Error
package.json must have a valid name field
Error message
package.json must have a valid name field
What it means
After successfully parsing the manifest, linkPlugin requires a non-empty string `name` field, since the name is used to place the symlink under plugins/node_modules. This error is thrown when package.json parses but has no usable name.
Source
Thrown at packages/coding-agent/src/extensibility/plugins/installer.ts:167
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);
// For scoped packages, ensure the scope directory exists
if (pkg.name.startsWith("@")) {
const scopeDir = path.join(PLUGINS_DIR, "node_modules", pkg.name.split("/")[0]);View on GitHub (pinned to 9690622007)
Solutions
- Add a valid npm-style `name` field to the target package.json
- Ensure the name is a non-empty string without `..`, backslashes, or extra slashes (scoped names with exactly one slash are allowed)
- Re-run linkPlugin after fixing the manifest
Example fix
// before
{ "version": "1.0.0" }
// after
{ "name": "my-plugin", "version": "1.0.0" } Defensive patterns
Strategy: validation
Validate before calling
const pkg = await Bun.file(path.join(dir, "package.json")).json();
if (typeof pkg.name !== "string" || pkg.name.length === 0) {
throw new Error(`package at ${dir} needs a non-empty string "name"`);
} Type guard
function hasValidName(pkg: unknown): pkg is { name: string } {
return typeof (pkg as { name?: unknown })?.name === "string" && (pkg as { name: string }).name.length > 0;
} Try / catch
try {
await linkPlugin(dir);
} catch (err) {
if (err instanceof Error && err.message === "package.json must have a valid name field") {
// add a name field then retry
}
throw err;
} Prevention
- Give every local package a valid npm-style name before linking
- Lint package.json against the npm name rules in CI for local packages
- Avoid generated/minimal manifests that omit the name field
When it happens
Trigger: linkPlugin(localPath, cwd) targets a package.json where `name` is missing, empty string, null, or a non-string (number/object) — common for private scratch packages and fresh `npm init -y` outputs that inherited no name in unusual setups.
Common situations: Private libraries with `"name": ""` or omitted name; manifests written by custom tooling that only includes dependencies; hand-built test fixtures missing the name field.
Related errors
- OpenAI Files API upload response is missing a file id
- ${destination} response did not include ${key}
- Invalid package name: ${name}
- Invalid characters in package name: ${name}
- Invalid path: ${localPath} resolves outside working director
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/56003b45e0cab098.
Report an issue: GitHub.