Commit No Bug
Published on

Why Your Next.js Blog Build Crashes With a Spawn Error

Authors
Landscape tech illustration showing a local Next.js build failing with a red ‘spawn error’ alert, highlighted workflow arrows, and warning icons on a blue indigo/cyan background.

First of all, the Tailwind Nextjs Starter Blog is AMAZING, created by Timothy Lin, and I am very grateful to him for such a fabulous piece of work.

Once I decided to build it locally, I hit this during build:

node:events:485
      throw er; // Unhandled 'error' event
      ^
Error: spawn blog/tailwind-nextjs-starter-blog-main ENOENT
    at ChildProcess._handle.onexit (node:internal/child_process:286:19)
    ...
{
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn blog/tailwind-nextjs-starter-blog-main',
  path: 'blog/tailwind-nextjs-starter-blog-main',
  spawnargs: [ 'next', 'build' ]
}

Here's the error I hit: Node throws an unhandled error event, and it says - spawn blog/tailwind-nextjs-starter-blog-main, ENOENT. ENOENT is a standard error code meaning 'no such file or directory' - so Node is telling us it tried to run something at that path, and it simply doesn't exist there. Looking at the object below, errno: -2, code ENOENT - same info, just structured. Then syscall and path both confirm the same broken path, and spawnargs shows it was trying to pass the next build as arguments to it. So all four fields are pointing to the same root cause: Node tried to execute that folder path directly instead of running next build inside it.

But why is it trying to run blog/tailwind-nextjs-starter-blog-main? That's not a command - it is part of a path.

The Build Script

The answer is in the build command:

"build": "cross-env INIT_CWD=$PWD next build && cross-env NODE_OPTIONS='--experimental-json-modules' node ./scripts/postbuild.mjs"

Look closely at this part: INIT_CWD=$PWD - $PWD is unquoted.

What actually happens

In POSIX shell, an unquoted variable expansion gets word-splitting on whitespace. POSIX is a standard that defines how Unix-like systems behave, including shell rules like this one. npm runs scripts via sh -c, so these rules apply.

If your directory path contains a space, say /home/jack/dev blog/tailwind-nextjs-starter-blog-main, the shell splits $PWD at the space and produces two tokens:

INIT_CWD=/home/jack/dev    blog/tailwind-nextjs-starter-blog-main

cross-env normally receives two things: the env var assignment, and a command to run. The unquoted $PWD causes the shell to split the command line into multiple tokens, which is what cross-env then receives:

  • INIT_CWD=/home/jack/dev (env var assignment, truncated at the space)
  • blog/tailwind-nextjs-starter-blog-main - (this becomes the command token)
  • next build (these end up as arguments to that spawned command)

At that point, Node tries to spawn the “command” token: blog/tailwind-nextjs-starter-blog-main, and fails with ENOENT because no such executable exists at that path.

The error confirms it: syscall: 'spawn blog/...' is the executable Node tried to run, and spawnargs: [ 'next', 'build' ] are the arguments it attempted to pass to it.

The Fix

Rename the folder. No spaces, no problem - my-blog or myblog instead of my blog.

If you want to keep the space, you can fix it in package.json by quoting $PWD:

"build": "cross-env INIT_CWD=\"$PWD\" next build && ..."

Why it works:

The shell expands $PWD, and the double quotes prevent word splitting, so cross-env receives the full path as one value.

Conclusion

Once you know that unquoted variables get word-split, the error stops feeling mysterious. The space in your directory name splits $PWD, cross-env ends up trying to spawn the leftover path fragment (blog/...), so Node throws ENOENT.

And once you learn that layer below the tool, a whole category of “mysterious build failures” suddenly becomes straightforward.

Found this helpful? Please share it with someone who also might find it helpful. Would you like more posts from me? Subscribe to the newsletter. Got questions? Send an email to commitnobug@outlook.com.