Docs menu
Troubleshooting Node.js
Common build and runtime errors for Node.js apps on Primcloud, with the fix for each.
On this page
Two places to look when a deploy misbehaves:
- Build log: the Deployments tab streams the full output from the build. Node.js version resolution, package manager install, build scripts, and dev-dependency pruning all surface here.
- Runtime log: the Logs tab streams
stdoutandstderrfrom your running pods. Startup crashes, unhandled promise rejections, and native-load failures show up here.
This page lists the errors that come up most often, in the order they'd typically bite you: detection, runtime resolution, package install, build scripts, then runtime.
Common build errors#
No Node.js application found#
The build looked for a package.json at the repo root and didn't find one.
Fix. Move the package.json to the repo root, or open a monorepo subdirectory as its own Primcloud app.
Unknown Node.js version#
The engines.node range in package.json doesn't match any version the Primcloud Runtime ships. Either the version isn't a real Node.js release, it's an unsupported major (21, 23, or older than what the Runtime still ships), or you pinned a patch that hasn't been added to the Runtime yet.
Fix. Bump to a version listed in Runtime versions, or loosen the range from an exact version to "24.x" so the resolver can pick a close match.
Node.js version is End-of-Life#
The build log prints a warning: Node.js <version> is now End-of-Life (EOL). The build still succeeds today, but in a future Runtime update this becomes a build error and the version is removed from the Runtime.
Fix. Bump engines.node to a supported major before the version is removed. See When a version drops out of support.
Missing lockfile / dependencies not installed#
The build log shows the runtime installing but no node_modules install step. Your app has a package.json but none of package-lock.json, pnpm-lock.yaml, or yarn.lock.
Fix. Run npm install, pnpm install, or yarn install locally, commit the generated lockfile, and redeploy. See Package managers → Lockfiles.
Wrong lockfile / package manager mismatch#
package.json declares "packageManager": "pnpm@..." (or engines.pnpm) but the repo ships a package-lock.json. The build tries to run pnpm and fails because pnpm-lock.yaml is missing, or worse, picks the wrong manager entirely.
Fix. Ship the lockfile matching your chosen manager, and delete lockfiles for other managers. Only one of package-lock.json, pnpm-lock.yaml, yarn.lock should exist in the repo.
npm ci / pnpm install / yarn install fails#
The lockfile disagrees with package.json. Common causes: a manual edit to package.json without regenerating the lockfile, a merge that resolved package.json but not the lockfile, or a dependency using a git or file URL that isn't reachable from the build environment.
Fix. Reproduce locally with the same command the build runs:
npm ci
pnpm install --frozen-lockfile
yarn install --immutable # Yarn 2+
yarn install --frozen-lockfile # Yarn 1
If it fails locally with the same error, the fix is the same: regenerate the lockfile, address the version conflict, or make the dependency URL reachable. If it passes locally, check that the lockfile is actually committed (git status in a fresh clone).
Build script failed: heroku-prebuild / heroku-build / build / heroku-postbuild#
One of your build scripts exited non-zero. The script output is in the build log directly above Primcloud's own error message.
Fix. Read the script's stderr and address it. Reproduce locally with the same command:
npm run build
Common causes: TypeScript compile errors, missing environment variables the build needs (set them in the Secrets panel), out-of-memory errors during a bundler run (see Debugging tips below).
Native module fails to compile: node-gyp errors#
An npm dependency with a native addon (sharp, bcrypt, sqlite3, canvas, etc.) failed to build. The node-gyp output above Primcloud's error usually names the missing header or library.
Fix. Two paths:
- If the package publishes prebuilt binaries (most modern ones do) and the build is trying to compile from source anyway, check the package's install docs. You may need to set an env var like
SHARP_IGNORE_GLOBAL_LIBVIPS=1in the Secrets panel to force the prebuilt path. - If the package needs an OS-level library (
libvips,libpq, ImageMagick), declare it inproject.toml; see Customizing the build → Debian packages.
Cannot find module '...'#
A require() or import resolves to nothing.
Fix. Common causes:
- The module is a
devDependencyand you install with pnpm or Yarn, so the build pruned it after the build scripts. Move it intodependencies. That's where every runtime import belongs. With npm, adevDependencystays installed. - The build script writes files that aren't checked into git (e.g. generated code) and no build step regenerates them on deploy. Add the generator to
heroku-postbuildorbuild. - A relative import has the wrong case. macOS and Windows filesystems are case-insensitive; Linux isn't.
import Foo from './foo'works locally and fails on Primcloud.
Common runtime errors#
App doesn't bind to $PORT#
Symptom: the deployment reaches Release Succeeded but the URL returns a connection error, and the runtime log has no "listening" line.
Fix. Every HTTP server on the web formation must listen on process.env.PORT. Primcloud sets it; hardcoded ports (3000, 8080) aren't reachable from the outside.
const port = process.env.PORT || 3000
app.listen(port, () => console.log(`listening on ${port}`))
Bind to 0.0.0.0 or omit the host entirely. Never use 127.0.0.1 on the web formation.
App exits immediately on start#
The runtime log shows the process starting and exiting with no other output, or an uncaught exception right at startup.
Most common causes:
- Missing required env var. If your app reads a database URL or API key from an env var and throws when it's missing, set the value in the Secrets panel and redeploy.
startscript not defined. If there's noProcfileand nostartscript inpackage.json, Primcloud falls back tonode index.js/node server.js. If neither of those files exists, the pod has nothing to run. Add aProcfileor astartscript.- Wrong entry point.
npm startruns whatever yourstartscript says. Verify it points at the actual entry file, not a stale one.
Out of memory on start or during build#
The build log or runtime log shows FATAL ERROR: Reached heap limit Allocation failed.
Fix. Two axes:
- At build time (typically during a bundler run): reduce parallelism (
NODE_OPTIONS=--max-old-space-size=2048). - At runtime: move to a larger compute size, or set
NODE_OPTIONS=--max-old-space-size=<mb>in the Secrets panel to give V8 a higher heap limit.
Native addon fails to load at runtime#
Error: Cannot find module '/app/node_modules/sharp/build/Release/sharp.node'
or
Error: /lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_...' not found
A native addon compiled successfully but can't load, often because the OS-level library it needs isn't present, or the addon was built for a different architecture.
Fix. Declare the missing library in project.toml. See Customizing the build → Debian packages.
Debugging tips#
- Reproduce the install locally.
npm ci,pnpm install --frozen-lockfile, or the Yarn equivalent. These are the exact commands the build runs. Most install failures reproduce this way. - Reproduce the build locally.
npm run buildruns yourbuildscript with the same env the build sees, minus the platform-set variables. If it works locally, the diff is usually an env var. Check what your build script reads fromprocess.envand mirror those values. - Check the resolved Node.js version. The build log's
Installing Node.js distributionsection names the exact version installed. If it's not what you asked for, yourengines.noderange is looser than you thought. Tighten it. - Turn on richer logs temporarily. Set
DEBUG=*(or a narrower namespace likeDEBUG=express:*) in the Secrets panel to make debug-namespaced modules emit their trace output. - Peel apart install vs. build vs. start. When you don't know which phase is failing, the build log timestamps and phase headers (
Installing Node.js,Installing node modules,Running scripts,Configuring default processes) tell you exactly where the last successful step was.