{"record":{"id":"56003b45e0cab098","repo":"can1357/oh-my-pi","slug":"package-json-must-have-a-valid-name-field","errorCode":null,"errorMessage":"package.json must have a valid name field","messagePattern":"package\\.json must have a valid name field","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/plugins/installer.ts","lineNumber":167,"sourceCode":"\tif (!normalizedPath.startsWith(`${normalizedCwd}/`) && normalizedPath !== normalizedCwd) {\n\t\tthrow new Error(`Invalid path: ${localPath} resolves outside working directory`);\n\t}\n\n\t// Validate package.json exists\n\tconst pkgFile = Bun.file(path.join(absolutePath, \"package.json\"));\n\tif (!(await pkgFile.exists())) {\n\t\tthrow new Error(`package.json not found at ${absolutePath}`);\n\t}\n\n\tlet pkg: { name?: string };\n\ttry {\n\t\tpkg = await pkgFile.json();\n\t} catch (err) {\n\t\tthrow new Error(`Invalid package.json at ${absolutePath}: ${err}`);\n\t}\n\n\tif (!pkg.name || typeof pkg.name !== \"string\") {\n\t\tthrow new Error(\"package.json must have a valid name field\");\n\t}\n\n\t// Validate package name to prevent path traversal via pkg.name\n\tif (pkg.name.includes(\"..\") || pkg.name.includes(\"/\") || pkg.name.includes(\"\\\\\")) {\n\t\t// Exception: scoped packages have one slash\n\t\tif (!pkg.name.startsWith(\"@\") || (pkg.name.match(/\\//g) || []).length !== 1) {\n\t\t\tthrow new Error(`Invalid package name in package.json: ${pkg.name}`);\n\t\t}\n\t}\n\n\tawait ensurePluginsDir();\n\n\t// Create symlink in plugins/node_modules\n\tconst linkPath = path.join(PLUGINS_DIR, \"node_modules\", pkg.name);\n\n\t// For scoped packages, ensure the scope directory exists\n\tif (pkg.name.startsWith(\"@\")) {\n\t\tconst scopeDir = path.join(PLUGINS_DIR, \"node_modules\", pkg.name.split(\"/\")[0]);","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/plugins/installer.ts#L149-L185","documentation":"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.","triggerScenarios":"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.","commonSituations":"Private libraries with `\"name\": \"\"` or omitted name; manifests written by custom tooling that only includes dependencies; hand-built test fixtures missing the name field.","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"],"exampleFix":"// before\n{ \"version\": \"1.0.0\" }\n// after\n{ \"name\": \"my-plugin\", \"version\": \"1.0.0\" }","handlingStrategy":"validation","validationCode":"const pkg = await Bun.file(path.join(dir, \"package.json\")).json();\nif (typeof pkg.name !== \"string\" || pkg.name.length === 0) {\n\tthrow new Error(`package at ${dir} needs a non-empty string \"name\"`);\n}","typeGuard":"function hasValidName(pkg: unknown): pkg is { name: string } {\n\treturn typeof (pkg as { name?: unknown })?.name === \"string\" && (pkg as { name: string }).name.length > 0;\n}","tryCatchPattern":"try {\n\tawait linkPlugin(dir);\n} catch (err) {\n\tif (err instanceof Error && err.message === \"package.json must have a valid name field\") {\n\t\t// add a name field then retry\n\t}\n\tthrow err;\n}","preventionTips":["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"],"tags":["package-json-invalid","validation","plugins","missing-field"],"backgroundTag":"package-name-missing-or-invalid","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}