pnpm/pnpm · error · PnpmError
INVALID_PACKAGE_NAME
INVALID_PACKAGE_NAME
Error message
Package in ${target} must have a name to get bin linked. What it means
When linking bins for a package under node_modules, the linker accepts `bin` as an object (`{ 'cmd': 'file.js' }`) or as a string shorthand whose command name is derived from `manifest.name`. If `bin` is a string but the manifest has no `name`, the command name cannot be derived, so it throws INVALID_PACKAGE_NAME.
Source
Thrown at pnpm11/bins/linker/src/index.ts:220
},
target: string
): Promise<CommandInfo[]> {
const manifest = opts.allowExoticManifests
? (await safeReadProjectManifestOnly(target) as DependencyManifest)
: await safeReadPkgJson(target)
if (manifest == null) {
// There's a directory in node_modules without package.json: ${target}.
// This used to be a warning but it didn't really cause any issues.
return []
}
if (isEmpty(manifest.bin) && !await isFromModules(target)) {
opts.warn(`Package in ${target} must have a non-empty bin field to get bin linked.`, 'EMPTY_BIN')
}
if (typeof manifest.bin === 'string' && !manifest.name) {
throw new PnpmError('INVALID_PACKAGE_NAME', `Package in ${target} must have a name to get bin linked.`)
}
return getPackageBinsFromManifest(manifest, target)
}
async function getPackageBinsFromManifest (manifest: DependencyManifest, pkgDir: string): Promise<CommandInfo[]> {
const cmds = await getBinsFromPackageManifest(manifest, pkgDir)
let nodeExecPath: string | undefined
if (manifest.engines?.runtime && runtimeHasNodeDownloaded(manifest.engines.runtime)) {
const require = createRequire(import.meta.dirname)
// Using Node.js’ resolution algorithm is the most reliable way to find the Node.js
// package that comes from this CLI's dependencies, because the layout of node_modules can vary.
// In an isolated layout, it will be located in the same node_modules directory as the CLI.
// In a hoisted layout, it may be in one of the parent node_modules directories.
const nodeDir = path.dirname(require.resolve('node/CHANGELOG.md', { paths: [pkgDir] }))
if (nodeDir) {
nodeExecPath = path.join(nodeDir, IS_WINDOWS ? 'node.exe' : 'bin/node')
}View on GitHub (pinned to 5b11d3a15b)
Solutions
- Add `"name": "your-pkg"` to the package.json at the path shown in the error
- Or switch `bin` to the explicit object form: `"bin": { "your-cmd": "./cli.js" }`, which does not depend on `name`
- Re-run the install/link after saving the manifest
Example fix
// before (package.json)
{
"version": "0.1.0",
"bin": "./cli.js"
}
// after
{
"name": "my-cli",
"version": "0.1.0",
"bin": "./cli.js"
}
// alternative: "bin": { "my-cli": "./cli.js" } Defensive patterns
Strategy: type-guard
Validate before calling
const manifest = JSON.parse(await fs.readFile(pkgJsonPath, 'utf8'))
if (typeof manifest.bin === 'string' && !manifest.name) {
throw new Error(`${pkgJsonPath}: string "bin" requires a "name" — fix before install`)
} Type guard
interface BinManifest { name?: string, bin?: unknown }
function hasLinkableBin (m: BinManifest): boolean {
if (m.bin == null) return false
if (typeof m.bin === 'object') return Object.keys(m.bin).length > 0
// string shorthand: only linkable when a name exists to derive the command from
return typeof m.name === 'string' && m.name.length > 0
} Prevention
- Always set `name` in package.json for any package that declares bins
- Prefer the object form of `bin` (`{ 'cmd': 'file.js' }`) so linking never depends on `name`
- Validate fixtures and generated manifests with a lint step before they reach install
When it happens
Trigger: `pnpm install`/`pnpm link` processing a dependency (often a git dep, `file:` dep, or symlinked local package) whose package.json has `"bin": "./cli.js"` but no `name` field.
Common situations: Local scaffolding packages or test fixtures written without a name; generated manifests; git dependencies with minimal package.json; linking a work-in-progress package before its manifest is finalized.
Related errors
- GLOBAL_BIN_CONFLICT
- NO_PKG_MANIFEST
- Failed to remove Windows bin shims for ${cmd}
- FROZEN_STORE_NEEDS_BUILD
- PATCH_FILE_PATH_MISSING
AI-assisted analysis of pnpm/pnpm@5b11d3a15b (2026-08-16).
Data as JSON: /api/errors/47a422b3b56b6911.
Report an issue: GitHub.