pnpm/pnpm · error · TypeError
hooks.readPackage should be a function
Error message
hooks.readPackage should be a function
What it means
requirePnpmfile validates the shape of every loaded pnpmfile: if `hooks.readPackage` is present but not a function, it throws a plain TypeError 'hooks.readPackage should be a function'. This is a pnpmfile contract violation (programmer error), not a PnpmError, so it carries no ERR_PNPM_* code.
Source
Thrown at pnpm11/hooks/pnpmfile/src/requirePnpmfile.ts:65
try {
let pnpmfile: Pnpmfile
// Check if it's an ESM module (ends with .mjs)
if (pnpmFilePath.endsWith('.mjs')) {
const url = pathToFileURL(path.resolve(pnpmFilePath)).href
pnpmfile = await import(url)
} else {
// Use require for CommonJS modules
pnpmfile = require(pnpmFilePath)
}
if (typeof pnpmfile === 'undefined') {
logger.warn({
message: `Ignoring the pnpmfile at "${pnpmFilePath}". It exports "undefined".`,
prefix,
})
return { pnpmfileModule: undefined }
}
if (pnpmfile?.hooks?.readPackage && typeof pnpmfile.hooks.readPackage !== 'function') {
throw new TypeError('hooks.readPackage should be a function')
}
if (pnpmfile?.hooks?.readPackage) {
const readPackage = pnpmfile.hooks.readPackage as Function // eslint-disable-line
pnpmfile.hooks.readPackage = async function (pkg: PackageManifest, ...args: any[]) { // eslint-disable-line
pkg.dependencies = pkg.dependencies ?? {}
pkg.devDependencies = pkg.devDependencies ?? {}
pkg.optionalDependencies = pkg.optionalDependencies ?? {}
pkg.peerDependencies = pkg.peerDependencies ?? {}
const newPkg = await readPackage(pkg, ...args)
if (!newPkg) {
throw new BadReadPackageHookError(pnpmFilePath, 'readPackage hook did not return a package manifest object.')
}
const dependencies = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const
for (const dep of dependencies) {
if (newPkg[dep] != null && (typeof newPkg[dep] !== 'object' || Array.isArray(newPkg[dep]))) {
throw new BadReadPackageHookError(pnpmFilePath, `readPackage hook returned package manifest object's property '${dep}' must be an object.`)
}
}View on GitHub (pinned to 5b11d3a15b)
Solutions
- Export readPackage as a real function: `module.exports = { hooks: { readPackage: (pkg) => pkg } }`
- Check sibling validations in the same loader: hooks.beforePacking must also be a function if present
- If the hook is not needed, remove the readPackage key entirely instead of leaving a non-function value
Example fix
// before
module.exports = { hooks: { readPackage: { transform: true } } }
// after
module.exports = { hooks: { readPackage: (pkg) => pkg } } Defensive patterns
Strategy: type-guard
Validate before calling
const mod = require(pnpmfilePath)
if (mod?.hooks?.readPackage != null && typeof mod.hooks.readPackage !== 'function') {
throw new TypeError(`pnpmfile ${pnpmfilePath}: hooks.readPackage must be a function`)
} Type guard
function hasValidReadPackage (pnpmfile: unknown): boolean {
const hooks = (pnpmfile as { hooks?: Record<string, unknown> })?.hooks
const rp = hooks?.readPackage
return rp == null || typeof rp === 'function'
} Try / catch
try {
await requirePnpmfile(file, prefix)
} catch (err: unknown) {
if (util.types.isNativeError(err) && err.message === 'hooks.readPackage should be a function') {
// the pnpmfile exports readPackage as a non-function: fix its shape
}
throw err
} Prevention
- Type pnpmfiles in TypeScript using the published hooks interface so shape errors surface at compile time
- Keep hooks as a plain object of functions; do not put configuration under hooks
- Validate a new or generated pnpmfile with a require + typeof check in a test
When it happens
Trigger: A pnpmfile exports `hooks: { readPackage: {...} }` (an object instead of a function), a string, or a mis-shaped default export; exporting a config object intended for another tool under hooks.
Common situations: Pnpmfile written against a different hooks API shape; copy-paste placing the function under the wrong key; a build step generating the pnpmfile with wrong output.
Related errors
- BAD_READ_PACKAGE_HOOK_RESULT
- hooks.beforePacking should be a function
- PNPMFILE_NOT_FOUND
- DUPLICATE_FINDER
- CONFIG_IS_UNDEFINED
AI-assisted analysis of pnpm/pnpm@5b11d3a15b (2026-08-16).
Data as JSON: /api/errors/e45deefdddae1e5e.
Report an issue: GitHub.