Skip to content

Cypress unable to load config file when using cypress-io/github-action@v6 #1408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ThomasTrepanier opened this issue Mar 21, 2025 · 25 comments
Closed
Assignees
Labels

Comments

@ThomasTrepanier
Copy link

Problem

Starting around 2pm UTC, our GH Action workflow that runs our Cypress test started failing with the following error:

Your configFile is invalid: /home/runner/_work/repo/cypress.config.ts

It threw an error when required, check the stack trace below:

SyntaxError: Unexpected token ':'
    at compileSourceTextModule (node:internal/modules/esm/utils:340:16)
    at ModuleLoader.importSyncForRequire (node:internal/modules/esm/loader:316:18)
    at loadESMFromCJS (node:internal/modules/cjs/loader:1371:24)
    at Module._compile (node:internal/modules/cjs/loader:1511:5)
    at Module._extensions..js (node:internal/modules/cjs/loader:1613:10)
    at Module.load (node:internal/modules/cjs/loader:1275:32)
    at Module._load (node:internal/modules/cjs/loader:1096:12)
    at Module.require (node:internal/modules/cjs/loader:1298:19)
    at require (node:internal/modules/helpers:182:18)
    at loadFile (/home/runner/.cache/Cypress/14.0.3/Cypress/resources/app/node_modules/@packages/server/lib/plugins/child/run_require_async_child.js:89:14)
    at EventEmitter.<anonymous> (/home/runner/.cache/Cypress/14.0.3/Cypress/resources/app/node_modules/@packages/server/lib/plugins/child/run_require_async_child.js:116:[38](https://github.com/MaintainX/maintainx/actions/runs/13992893889/job/39180664735#step:14:39))
    at EventEmitter.emit (node:events:524:28)
    at process.<anonymous> (/home/runner/.cache/Cypress/14.0.3/Cypress/resources/app/node_modules/@packages/server/lib/plugins/util.js:33:22)
    at process.emit (node:events:524:28)
    at emit (node:internal/child_process:950:14)
    at process.processTicksAndRejections (node:internal/process/task_queues:83:21)

Root cause investigation

We investigated the following leads, but we kept getting the same error:

Locally

1- Reproduce the issue locally
We weren't able to reproduce the issue locally, even from a freshly cloned repository.

In CI

1- Verify that the cypress.config.ts file is valid
We couldn't find any unexpected : character in the config file itself (config provided below)

2- Confirm we didn't change anything related to cypress or CI or the E2E framework on our side
We last changed the config file 2 weeks ago and the workflow had succeeded multiple times since. We haven't change our workflow files or even the E2E tests since the error started.

3- Look into changes to Cypress, this action or plugins we use
There doesn't seem to have been changes to the plugins we use nor this action. Cypress did merge some new drivers this morning but it is unclear if that could be the issue since those drivers are probably not released yet.

4- Updating Cypress to the latest version (14.2.0)
This led to the same error.

5- Change the extension of the config to .mts
We tried forcing the file to be loaded as ESM, but the cypress code to load the config always tries to load the config file as a CJS module first (see the implementation here )

6- Change which runners are used by the workflow
We used new runners to try to have a fresh environment for Cypress, but this led to the same error.

Solution

We tried to use the cypress cli to run the tests instead of this action.
We set up the same services, same config file and same spec list to be run with the cypress cli cypress run. This worked, the config was parsed properly, and the tests were run successfully.

Environment

cypress.config.ts file
// @ts-expect-error - cypress grep plugin is not typed
import cypressGrepPlugin from "@cypress/grep/src/plugin.js";

import { allureCypress } from "allure-cypress/reporter";
import { defineConfig } from "cypress";
import cypressOnFix from "cypress-on-fix";
import cypressSplit from "cypress-split";
import vitePreprocessor from "cypress-vite";
import * as dotEnv from "dotenv";
import dotEnvExpand from "dotenv-expand";
import fs from "node:fs";
import { rmdir } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const isCI = process.env.CI === "true";
const dotenvFiles = isCI ? [".env.ci", ".web.env.ci"] : [".env", ".web.env"];

dotenvFiles.forEach((dotenvFile) => {
  const dotenvFullPath = path.resolve("../../config", dotenvFile);
  dotEnvExpand(
    dotEnv.config({
      path: dotenvFullPath,
    }),
  );
});

let baseUrl = process.env.PUBLIC_API_URI || "";
if (process.env.HTTP !== "true") {
  baseUrl = baseUrl.replace("http://", "https://");
} else {
  baseUrl = baseUrl.replace("https://", "http://");
}

export default defineConfig({
  viewportWidth: 1200,
  retries: {
    runMode: 2,
    openMode: 0,
  },
  video: !!isCI,
  chromeWebSecurity: false,
  numTestsKeptInMemory: 1,
  defaultCommandTimeout: 10000,
  responseTimeout: 45000,
  e2e: {
    baseUrl,
    downloadsFolder: path.join(__dirname, "cypress/downloads"),
    supportFile: "cypress/support/index.ts",
    specPattern: "cypress/integration/**/*.spec.ts",
    excludeSpecPattern: isCI ? "cypress/integration/smoke-tests/**/*.spec.ts" : [],
    experimentalRunAllSpecs: true,
    async setupNodeEvents(on, config) {
      // Allows to have multiple listeners for the same event
      on = cypressOnFix(on);

      cypressSplit(on, config);
      on(
        "file:preprocessor",
        vitePreprocessor({
          resolve: {
            preserveSymlinks: true,
          },
        }),
      );

      on("task", {
        async cleanDownloadFolder() {
          await rmdir(config.downloadsFolder, { maxRetries: 10, recursive: true }).catch((err) => {
            if (err.code !== "ENOENT") {
              throw err;
            }
          });
          // Returning undefined here would make the task fail
          return null;
        },
        info(message) {
          logMessage(message);
          return null;
        },
        error(message) {
          logMessage(message, true);
          return null;
        },
        warn(message) {
          logMessage(message, false, true);
          return null;
        },
        saveLogs(logMessages) {
          const logDir = path.join(config.downloadsFolder, "logs");
          const logFilePath = path.join(logDir, "logs.txt");
          fs.mkdirSync(logDir, { recursive: true });
          fs.appendFileSync(logFilePath, logMessages.join("\n") + "\n", "utf8");
          return null;
        },
      });

      function logMessage(message: string, isError = false, isWarning = false) {
        let logMethod;
        if (isError) {
          logMethod = console.error;
        } else if (isWarning) {
          logMethod = console.warn;
        } else {
          logMethod = console.log;
        }
        logMethod(message);
      }

      // Suggestion by garyburgmann: https://github.com/cypress-io/cypress/issues/7204#issuecomment-810774449
      // https://github.com/cypress-io/cypress/issues/349
      // add --disable-dev-shm-usage chrome flag
      on("before:browser:launch", (browser, launchOptions) => {
        if (browser.family === "chromium" && browser.name !== "electron") {
          launchOptions.args.push("--disable-dev-shm-usage");
        }
        return launchOptions;
      });

      cypressGrepPlugin(config);

      allureCypress(on, config, {
        resultsDir: "./allure-results",
      });

      // IMPORTANT: return the config object
      return config;
    },
  },
  env: {
    grepFilterSpecs: true,
    grepOmitFiltered: true,
    ...process.env,
  },
});

Plugins used:

  • Cypress Grep
  • Cypress Split
  • Allure Report
  • Cypress On Fix
  • cypress-vite

Cypress version: 14.2.0

Package manager: yarn

Node version: 22.14.0

I created the issue in this project since not using this action solved the problem. I wasn't able to find the exact cause for this, but it looks like it's related to this github action.

Thank you for looking into this!

@MikeMcC399
Copy link
Collaborator

@ThomasTrepanier

This issue is unlikely to be caused by cypress-io/github-action itself. It sounds more like it might be a Node.js incompatibility.

Would you like to post your GitHub Actions workflow here?

In the logs I can see

.cache/Cypress/14.0.3

which is not the same as "Cypress version: 14.2.0" in the text.

@MikeMcC399 MikeMcC399 self-assigned this Mar 21, 2025
@ThomasTrepanier
Copy link
Author

@MikeMcC399
You are right. After more investigation, it was found that our Github runners were updated to v2.323.0 since the problem started. In this version they bumped the node version to 20.19 here.

In that version they turned some features on by default. If we disable them using --no-experimental-require-module and --no-experimental-detect-module it works.

I can close the issue here and open one on their side.

As for the cache log, it was of an earlier run where we were still running with Cypress 14.0.3, but we had the same output under Cypress 14.2.0

@MikeMcC399
Copy link
Collaborator

MikeMcC399 commented Mar 21, 2025

@ThomasTrepanier

I suggest to close this issue, since it is not an action issue.

You can subscribe to Cypress releases by selecting the Watch option on https://github.com/cypress-io/cypress. They also get announced in Discord chat

@MikeMcC399

This comment has been minimized.

@achristmascarl
Copy link

@ThomasTrepanier

You can also pin to a fixed Node.js version with actions/setup-node

Pinning the Node version with actions/setup-node doesn't appear to work; the cypress-io/github-action README says:

Cypress itself runs with a fixed Node.js version specified by the runs.using parameter of action.yml. github-action@v6 uses node20.

And upon reviewing some of the previous CI runs with Cypress, the Node version from action/setup-node is not always the same as what cypress says it is using. for example, a run from yesterday:

Run actions/setup-node@v4:

Found in cache @ /opt/hostedtoolcache/node/20.19.0/x64
Environment details
  node: v20.19.0
  npm: 10.8.2
  yarn: 1.22.22

Run cypress-io/github-action@v6:

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Cypress:        13.15.0                                                                        │
  │ Browser:        Electron 118 (headless)                                                        │
  │ Node Version:   v20.18.0 (/home/runner/runners/2.322.0/externals/node20/bin/node)              │
  │ Specs:          6 found (********************************************************************) │
  │ Searched:       cypress/tests/api/**/*.ts                                                      │
  │ Experiments:    experimentalRunAllSpecs=true,experimentalWebKitSupport=true                    │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘

@AdrienPoupa
Copy link

AdrienPoupa commented Mar 21, 2025

If you are running with Node.js 20.19.0

"We" are not running anything, merely using whatever Node 20 version the GitHub runner provides. As explained by @achristmascarl, this action runs Cypress using Node 20 with no possibility to override, which would have been handy in this case.

As GitHub gradually rolls out the v2.323.0 of their runners, expect more users to have this issue.

@MikeMcC399
Copy link
Collaborator

MikeMcC399 commented Mar 21, 2025

@ThomasTrepanier / @achristmascarl / @AdrienPoupa

My apologies for the incorrect assessment of this issue!

@achristmascarl / @AdrienPoupa

You are entirely correct. actions/setup.node does not change the Node.js version which Cypress runs in when it is called via the action using the Cypress Module API.

This repo is still on
https://github.com/actions/runner/blob/v2.322.0/src/Misc/externals.sh
NODE20_VERSION="20.18.0"
meaning the issue cannot show up here in CI at this point in time.
Edit: rollout has completed

Those repos / organizations where
https://github.com/actions/runner/blob/v2.323.0/src/Misc/externals.sh
NODE20_VERSION="20.19.0"
has rolled out may be hitting the issue, depending on the configuration.
Edit: It appears to affect also projects using TypeScript with type: module using TypeScript syntax in cypress.config.ts (see cypress-io/cypress#30730)

According to https://nodejs.org/docs/latest/api/cli.html#node_optionsoptions
it should be possible to set environment variables for
--no-experimental-require-module and --no-experimental-detect-module
with NODE_OPTIONS

I can't test this at the moment, due to the fact that I don't have a failing workflow and this repo hasn't been migrated. Edit: now tested and reproduced.

Maybe @ThomasTrepanier could describe exactly how he applied his workaround?

@thiagomini
Copy link

thiagomini commented Mar 21, 2025

Warning

I found a workaround!

Edit: You can fix it by setting the --no-experimental-require-module and --no-experimental-detect-module flags in NODE_OPTIONS env var as @MikeMcC399 mentioned above. Here's how you might want to change the action:

      - name: Cypress e2e tests
        uses: cypress-io/github-action@v6
        with:
          browser: chrome
          tag: ${{ matrix.app }}
        env:
          # Add the option below
          NODE_OPTIONS: "--no-experimental-require-module --no-experimental-detect-module"

We're having a similar issue that just started today - nothing has changed in our repo:

 DevTools listening on ws://127.0.0.1:38553/devtools/browser/1c63d774-644c-4a50-8a85-6312283ee0e7
(node:2179) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("file%3A///home/runner/.cache/Cypress/14.2.0/Cypress/resources/app/node_modules/ts-node/esm/transpile-only.mjs", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)
Your configFile is invalid: /home/runner/work/apps/admin/cypress.config.ts

It threw an error when required, check the stack trace below:

Can someone confirm a workaround with details? Thanks!

@MikeMcC399

This comment has been minimized.

@thiagomini
Copy link

For anyone looking for a temporary solution, see my comment above

@MikeMcC399
Copy link
Collaborator

@thiagomini

Thanks for publishing the workaround! That was what I meant. ❤

@AdrienPoupa
Copy link

I can confirm NODE_OPTIONS: "--no-experimental-require-module" fixes it as a workaround. Unfortunately it was not an option for us as we're running our Node.js backend in the same job and it needs require(esm) 😅

@MikeMcC399
Copy link
Collaborator

MikeMcC399 commented Mar 22, 2025

The original issue reported here does not have enough information in order to reproduce it exactly, however it is possible to reproduce a similar issue with a TypeScript project:

  • using type module in package.json
  • and using TypeScript syntax in cypress.config.ts such as
    setupNodeEvents: (_, config: Cypress.PluginConfigOptions) => {
      return config
    },

There is no example like this in this repo and so the issue would not be shown in CI even if GitHub Actions had already rolled out [email protected] to this repo.

I set up a test for this in my own fork and I will check when the runner updates (edit: done) and when the next Cypress version is released (edit: still waiting).
If GitHub Actions telemetry is showing an unusual level of failures, they may be slowing down the rollout. In that case it could be that the Cypress fix arrives here faster than the runner rollout reaches this repo We will see!

The breaking change occurs because Node.js backported require(esm) into Node.js 20.19.0 and this is what [email protected] is currently rolling out to all JavaScript Actions. There is no choice here (at least as far as GitHub-hosted runners is concerned). The version is fixed and determined by GitHub as explained in their release notes:

"Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet."

@MikeMcC399
Copy link
Collaborator

@MikeMcC399
Copy link
Collaborator

ERR_MODULES_NOT_FOUND

@MikeMcC399
Copy link
Collaborator

MikeMcC399 commented Mar 25, 2025

Current status

The GitHub runner version '2.323.0' is now fully rolled out to GitHub-hosted runners.

Image

The following workaround can be applied if the runner image is set to run in Node.js 20.x or 22.x.

        env:
          NODE_OPTIONS: "--no-experimental-detect-module --no-experimental-require-module"

These are the defaults:

Runner Default Node.js NODE_OPTION usable
ubuntu-20.04 18.20.7 NO
ubuntu-22.04 18.20.7 NO
ubuntu-24.04 20.19.0 YES
windows-2019 18.20.7 NO
windows-2022 18.20.7 NO
windows-2025 22.14.0 YES
macos-13 20.19.0 YES
macos-14 20.19.0 YES
macos-15 22.13.0 YES

Planned Cypress fix

@MikeMcC399

This comment has been minimized.

@MikeMcC399
Copy link
Collaborator

MikeMcC399 commented Mar 26, 2025

@ThomasTrepanier

I'm seeing [email protected] now available from the npm registry.

You may like to try this out and check that your issue is resolved if you remove your previous workaround.

No change to cypress-io/github-action or to workflows is required, apart from ensuring that [email protected] or above is used.

@MikeMcC399
Copy link
Collaborator

Closing, as this was an issue with Cypress compatibility with Node.js 20.19.0 and it is resolved with the release of [email protected]

@pieterbos
Copy link

pieterbos commented Mar 27, 2025

This issue is fixed and worked around - but the cause of this happening again is not. Which is that the node js version of the github runners are used, which is just updated suddenly when github rolls out their new runners.

Would it not be better to at least offer the option of setting the node version of the cypress runner to a specific node version itself as well? Tests suddenly failing due to github runner updates are quite nasty to debug, and are disrupting many processes.

@MikeMcC399
Copy link
Collaborator

@pieterbos

This issue is fixed and worked around - but the cause of this happening again is not. Which is that the node js version of the github runners are used, which is just updated suddenly when github rolls out their new runners.

Would it not be better to at least offer the option of setting the node version of the cypress runner to a specific node version itself as well? Tests suddenly failing due to github runner updates are quite nasty to debug, and are disrupting many processes.

Thank you for your suggestion! Please open a new enhancement request for your suggestion and we can pick it up there.

@MikeMcC399
Copy link
Collaborator

@pieterbos

If you run Cypress using the command option, you can by-pass using the Cypress Module API and Cypress will run in the chosen Node.js version. Alternatives each have their advantages and disadvantages, which is why I suggested opening a new issue to avoid overloading this closed issue.

@pieterbos
Copy link

Thanks, will open new issue later today!

Command option is an alternative Indeed, with some drawbacks.

@ThomasTrepanier
Copy link
Author

@MikeMcC399 Thank you very much for your time. We will update to [email protected] and let you know if that helped.
In the meantime, we transitionned our config file to a JS file instead of a TS file and fixed the issue while still using this Action.

@MikeMcC399
Copy link
Collaborator

@ThomasTrepanier

Thank you very much for your time.

You're very welcome!

We will update to [email protected] and let you know if that helped. In the meantime, we transitionned our config file to a JS file instead of a TS file and fixed the issue while still using this Action.

It's good to hear what your plans are. Thank you for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants