Featured image of post Fixing ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION in GitHub Actions

Fixing ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION in GitHub Actions

Learn how to troubleshoot ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION in GitHub Actions, understand pnpm-workspace.yaml and allowBuilds, and resolve local versus CI installation differences.

Introduction

Recently, one of my GitHub Actions workflows failed during dependency installation:

Run pnpm install

ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION
packages field missing or empty

What made this issue confusing was that running pnpm install locally worked without any problems.

At first, I suspected that GitHub Actions was using frozen lockfile mode and that disabling it might solve the problem. However, after investigating the configuration, I found that the issue was related to pnpm-workspace.yaml rather than the lockfile itself.

This article documents the troubleshooting process and explains the relationship between pnpm workspaces, dependency build permissions, and CI environments.

1. Understanding the Error

The error message:

ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION
packages field missing or empty

indicates that pnpm encountered a workspace configuration it could not accept.

The relevant configuration file in my project was:

allowBuilds:
  '@parcel/watcher': true
  esbuild: true

Notice that the file contained only an allowBuilds property.

There was no packages property.

This raised two questions:

  • Why did a regular single-package project have a pnpm-workspace.yaml file?
  • Why did pnpm report a workspace configuration error when the project did not actually use a Monorepo structure?

To understand the problem, we first need to understand what this file does.

2. What Is pnpm-workspace.yaml?

pnpm-workspace.yaml is the configuration file pnpm uses to define workspace-level settings and manage multiple packages within a repository.

A typical Monorepo configuration looks like this:

packages:
  - 'packages/*'
  - 'apps/*'

Each matching directory can contain an independent package.json.

For example:

my-project/
├── package.json
├── pnpm-workspace.yaml
├── pnpm-lock.yaml
├── apps/
│   ├── web/
│   │   └── package.json
│   └── admin/
│       └── package.json
└── packages/
    ├── ui/
    │   └── package.json
    └── utils/
        └── package.json

This allows multiple projects to share dependencies and be managed from a single repository.

However, pnpm-workspace.yaml is not exclusively used to declare package directories. It also stores various pnpm configuration settings, including dependency build permissions.

That distinction is important for understanding this particular issue.

3. Why Was pnpm-workspace.yaml Created?

The key to this problem was the following configuration:

allowBuilds:
  '@parcel/watcher': true
  esbuild: true

These settings are related to pnpm’s dependency build-script approval mechanism.

Modern pnpm versions provide security controls for dependency lifecycle scripts, such as:

  • preinstall
  • install
  • postinstall

These scripts can execute code during dependency installation. Restricting their execution helps reduce supply-chain security risks.

When dependencies have build scripts that have not yet been reviewed, pnpm can request approval.

You can use:

pnpm approve-builds

This command allows you to review dependencies and decide which packages are permitted to execute their build scripts.

The approval decisions are recorded in pnpm-workspace.yaml.

For example:

allowBuilds:
  '@parcel/watcher': true
  esbuild: true

Here:

  • true means the dependency is allowed to execute its build scripts.
  • false means the dependency is explicitly denied permission.

Therefore, even if a project does not use a Monorepo structure, it may still need pnpm-workspace.yaml to store dependency build permissions.

Important: Do not assume that this file was created because you initialized a Monorepo. Running pnpm approve-builds or encountering unreviewed dependency build scripts during installation can also result in this configuration being written.

4. Why Does Local Installation Work but GitHub Actions Fail?

This was the most confusing part of the troubleshooting process.

The same command produced different results:

pnpm install

Local environment:

Installation completed successfully.

GitHub Actions:

ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION
packages field missing or empty

There are several things worth checking.

4.1 Different pnpm Versions

The first thing to investigate is whether the local environment and GitHub Actions are using the same pnpm version.

Check locally:

pnpm --version

Then check the version inside GitHub Actions:

- name: Check environment
  run: |
    node --version
    pnpm --version

Different pnpm versions may have different workspace configuration validation and dependency build approval behavior.

This is especially important when a project is developed locally with one pnpm version but installed in CI with another.

4.2 Different Installation Environments

Local environments may already contain:

  • An existing node_modules directory.
  • Previously downloaded packages.
  • Cached package artifacts.
  • Existing pnpm configuration.

GitHub Actions generally starts with a clean runner unless dependency caching is configured.

Consequently, the installation process may exercise different code paths.

However, this does not mean that local installation automatically ignores invalid workspace configuration. It is important to compare the pnpm versions and reproduce the installation using a clean environment before drawing that conclusion.

4.3 Check the GitHub Actions Configuration

A typical workflow may look like this:

name: CI

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 10

      - name: Install dependencies
        run: pnpm install

      - name: Build
        run: pnpm build

For reproducible builds, use a consistent pnpm version across local development and CI rather than relying on an unspecified version.

5. Does Frozen Lockfile Mode Cause This Error?

Initially, I suspected that GitHub Actions was failing because of frozen lockfile mode.

In CI environments, pnpm commonly enables --frozen-lockfile automatically when a lockfile exists.

You can explicitly disable it:

pnpm install --no-frozen-lockfile

However, this is not a reliable solution to an invalid workspace configuration.

There are two separate concepts:

ConfigurationPurpose
--frozen-lockfilePrevents pnpm from modifying the lockfile during installation
pnpm-workspace.yamlStores workspace definitions and pnpm settings

Disabling frozen lockfile mode does not repair an invalid workspace configuration.

It may also allow the lockfile to change during CI installation, making builds less reproducible.

Recommendation: Keep frozen lockfile mode enabled in CI unless there is a specific reason to disable it. Fix the underlying configuration instead.

6. How to Fix the Problem

The correct solution depends on whether your project actually uses a workspace.

Solution A: Keep pnpm-workspace.yaml

If you need allowBuilds to manage dependency build permissions, keeping the configuration file is perfectly reasonable.

For a Monorepo, declare the actual package directories:

packages:
  - 'packages/*'
  - 'apps/*'

allowBuilds:
  '@parcel/watcher': true
  esbuild: true

For a single-package project, do not invent package directories just to satisfy the configuration.

Check the documentation for the exact pnpm version you use. Current pnpm documentation allows the packages field to be omitted, in which case only the root package belongs to the workspace. Older versions or other configuration constraints may behave differently.

If your installed version explicitly rejects the missing or empty field, first verify the version and its supported workspace syntax rather than blindly adding an empty array.

Solution B: Remove pnpm-workspace.yaml

If your project does not need workspace-level configuration or dependency build approvals, you can remove the file.

rm pnpm-workspace.yaml

Then test the installation:

pnpm install

However, be aware that removing the file also removes the allowBuilds approval configuration.

If your dependencies require build scripts, you must configure their permissions using a mechanism supported by your pnpm version.

Do not assume that moving allowBuilds into the root package.json is a universal replacement. Its documented configuration location is pnpm-workspace.yaml.

7. How to Reproduce the Problem Locally

To investigate differences between local and CI environments, start with the following checks:

# Check Node.js version
node --version

# Check pnpm version
pnpm --version

# Inspect workspace configuration
cat pnpm-workspace.yaml

# Check package manager declaration
cat package.json

You can also perform a clean installation after preserving your existing lockfile:

rm -rf node_modules
pnpm install --frozen-lockfile

This helps determine whether the problem is related to existing installation artifacts.

Avoid deleting pnpm-lock.yaml just to reproduce the issue. Doing so may introduce unrelated dependency resolution changes.

8. Key Takeaways

This troubleshooting experience highlights several important points:

  1. pnpm-workspace.yaml is not only for Monorepos. It can also store pnpm configuration, including dependency build permissions.
  2. allowBuilds controls dependency lifecycle script permissions. It helps prevent unreviewed dependencies from executing arbitrary installation scripts.
  3. Local and CI environments should use consistent pnpm versions. Version differences can lead to different installation behavior.
  4. Frozen lockfile mode is not the root cause of workspace configuration errors. Disabling it does not repair an invalid configuration.
  5. Do not remove configuration files blindly. Understand why they exist before deciding whether they are necessary.

The most important lesson is to distinguish between workspace configuration problems and lockfile problems. They are separate mechanisms, and changing one does not necessarily fix the other.

References

comments powered by Disqus