Target: pnpm/pnpm
Issue: pnpm/pnpm#12222
PR: pnpm/pnpm#12327
Field Lab: https://github.com/scarab-systems/scarab-field-lab
This field test targeted a pnpm install failure where a long pnpm-created TMPDIR path could cause lifecycle tooling to exceed the Unix socket path length limit.
The issue shape is deceptively simple:
- pnpm install runs as root, commonly inside a container
- pnpm sets TMPDIR inside the pnpm store
- a git-hosted dependency runs lifecycle tooling during package preparation
- that tooling creates an IPC socket path under TMPDIR
- the full socket path becomes too long
- Node reports listen EINVAL
That visible error makes the failure look like it belongs to Node, tsx, the lifecycle script, or the package being prepared.
But the bounded pnpm-side repair lives somewhere smaller.
The failure was a path-budget problem.
The public case record for this field test is available in the Scarab Field Lab:
https://github.com/scarab-systems/scarab-field-lab
Failure shape
The reported failure happened during git-hosted dependency preparation.
pnpm created a temporary package directory under its store. That directory became the TMPDIR for lifecycle tooling. A lifecycle tool then created an IPC socket path below that temp directory.
The problem is that Unix domain socket paths have a hard length limit.
So the failure was not caused by the package simply “not building.” It was not caused by a missing dependency. It was not even, in the narrow repair sense, caused by the lifecycle tool creating an IPC socket.
The lifecycle tool was doing something normal: creating a socket under TMPDIR.
The problem was that the TMPDIR path pnpm handed to that tool had already consumed too much of the available path budget.
By the time the lifecycle tool appended its own socket path, the final path crossed the limit.
The visible symptom was:
listen EINVAL
But the diagnostic boundary was:
pnpm-owned temp path length versus lifecycle-owned socket path creation.
Boundary
The boundary here is:
pnpm-owned CAFS temporary package directory naming
versus
lifecycle tooling IPC socket paths created under TMPDIR
pnpm does not own every lifecycle script.
It does not own tsx.
It does not own the Unix socket path limit.
It does not own every file or socket a package tool may create under TMPDIR.
But pnpm does own the temporary directory path it gives those tools to work inside.
That is the repair surface.
The fix is not to special-case one package. It is not to patch around tsx. It is not to redesign lifecycle execution. It is not to claim that pnpm can prevent every possible socket path overflow.
The bounded pnpm-side repair is to stop spending unnecessary path length in the CAFS temp directory basename.
That gives lifecycle tools more room to create their own paths below TMPDIR.
What changed
The repair changes CAFS temp directory creation so pnpm uses a shorter generated basename.
The old path shape used a longer generated temp suffix.
The new path shape uses Node’s native temp directory creation with a short prefix:
ts fs.mkdtemp(path.join(baseTempDir, 'tmp'))
That keeps the temp directory inside the pnpm store’s temp area while reducing the basename length.
The patch also removes the path-temp dependency from @pnpm/store.create-cafs-store.
A regression test was added to prove that CAFS temp directories used during git package preparation keep a short basename.
The important part is not just that the name is shorter.
The important part is that pnpm preserves its ownership boundary:
- keep the pnpm-controlled temp root
- shorten the pnpm-controlled generated basename
- leave more room for lifecycle tools below TMPDIR
- avoid pretending to own the downstream lifecycle tool’s socket construction
That is a narrow repair.
Why the full SDS diagnose mattered
This case was opened as a full SDS field test.
SDS did not need a bespoke scoped run to find the right neighborhood.
That matters because the issue had multiple tempting surfaces:
- git-hosted dependency preparation
- root/container behavior
- lifecycle scripts
- Node IPC
- tsx
- pnpm store paths
- TMPDIR
- Unix socket limits
A human or agent could easily chase the loudest part of the stack trace.
The full diagnostic pass surfaced the runtime/temp-artifact neighborhood instead.
That is the purpose of the diagnostic layer.
Not to magically “know the fix.”
Not to invent a patch.
Not to replace maintainer review.
The useful diagnostic move was narrowing the ownership surface:
which part of this failure is pnpm’s to repair?
The answer was not “everything below the stack trace.”
The answer was the CAFS temp directory naming path.
Why this was not a lifecycle-script fix
It would be easy to frame this as a lifecycle tool failure because the crash happens while the lifecycle tool is creating an IPC socket.
But that would put the repair pressure in the wrong place.
The lifecycle tool needs a socket path. It creates that path under TMPDIR. That behavior may be entirely reasonable.
The Unix socket limit is also not negotiable from pnpm’s side.
So the question becomes:
Can pnpm reduce avoidable path length before lifecycle tools enter the picture?
Yes.
That is why shortening the CAFS temp basename is the right class of repair.
It does not make assumptions about the package. It does not depend on one lifecycle tool. It does not require pnpm to understand every downstream socket path. It simply gives the downstream process more path budget.
That is the semantic repair.
The bug is not “a tool used a socket.”
The bug is “pnpm consumed too much path budget before handing off to tools that reasonably create paths under TMPDIR.”
Validation
The repair was validated with focused and project-level pnpm checks.
The important validation point is that the regression proves the generated CAFS temp basename stays short during git package preparation.
For exact validation details, current upstream status, and the public case record, see the Field Lab:
https://github.com/scarab-systems/scarab-field-lab
Field test result
This was a clean path-budget boundary repair.
The issue reduced to:
- pnpm creates a temporary package directory under its store
- that directory becomes part of TMPDIR
- lifecycle tools create additional paths below TMPDIR
- Unix socket paths have a strict length limit
- pnpm can shorten the part of the path it owns
- shortening that basename leaves more room for lifecycle tools
That is the whole repair lane.
The patch does not claim to fix every possible IPC path failure. It does not claim to change Unix socket limits. It does not claim to fix tsx. It does not redesign pnpm lifecycle execution.
It fixes the pnpm-owned part of the path budget.
That is the kind of boundary Scarab/SDS is designed to surface.
Public claim
The correct claim for this field test is:
Scarab/SDS helped drive a bounded repair candidate for pnpm/pnpm#12222, where long pnpm-created TMPDIR paths could cause lifecycle tooling IPC socket paths to exceed the Unix socket path limit during git-hosted dependency preparation as root. A full SDS diagnose surfaced the runtime/temp-artifact neighborhood without requiring a bespoke scoped run. The upstream PR shortens CAFS temporary package directory names using fs.mkdtemp() with a short tmp prefix, removes path-temp from @pnpm/store.create-cafs-store, and adds regression coverage proving the generated CAFS temp basename stays short.
Disclosure: This field report was prepared with AI-assisted editing from my own field-test notes, public issue and PR records, validation summary, and repair record. The technical claims and final wording were reviewed before publication.
Top comments (0)