#3724·artillery

esbuild-wasm memory limit causes RangeError: Invalid array length when bundling TypeScript processors with large dependencies

Author: mmakwanaCertiniaCreated Apr 22, 2026Updated Apr 22, 2026

Describe the bug

When a TypeScript processor imports packages with large transitive dependency trees, Artillery's use of esbuild-wasm to bundle the processor fails with RangeError: Invalid array length. This is a hard memory ceiling imposed by the WebAssembly linear memory model — it is not a problem with the user's code or dependencies.

Artillery version: 2.0.30 esbuild-wasm version: ^0.19.12

Steps to reproduce

  1. Create a TypeScript processor that imports a package with a large transitive dependency tree (e.g. one that pulls in typeorm and its peers).
  2. Run an Artillery test that references this processor.
  3. Artillery calls esbuild.buildSync(...) via esbuild-wasm to compile it.

Error output

RangeError: Invalid array length

Root cause

lib/util/prepare-test-execution-plan.js uses esbuild-wasm to bundle TypeScript processors:

// line ~149 and ~191 const esbuild = require('esbuild-wasm'); esbuild.buildSync({ bundle: true, ... });

esbuild-wasm runs inside a WebAssembly sandbox with a fixed linear memory limit. When the bundled output (processor + all transitive dependencies) exceeds that limit, it throws RangeError: Invalid array length. Native esbuild, by contrast, uses a platform binary with no such constraint — the API is identical.

The code itself already contains an acknowledgement of this limitation:

//TODO: move require to top of file when Lambda bundle size issue is solved //must be conditionally required for now as this package is removed in Lambda for now to avoid bigger package sizes const esbuild = require('esbuild-wasm');

We understand esbuild-wasm is used to keep the Lambda deployment package small (the native esbuild binary adds ~7 MB per platform). However, this tradeoff penalises all non-Lambda users — CI runners, local development, dedicated test infrastructure — who have no need for WASM and no benefit from the smaller package size.

Suggested fix

Add a configuration option to select the esbuild variant, for example, via an Artillery config property:

config: { bundling: { esbuild: 'native' // or 'wasm' (default, preserves current behaviour) } } This would let users with large processors opt into native esbuild without affecting Lambda deployments that need esbuild-wasm.

An alternative would be to auto-detect the environment (e.g. check for AWS_LAMBDA_FUNCTION_NAME) and fall back to native esbuild when not running in Lambda.

Workaround

Until this is fixed, it is possible to patch Artillery post-install by replacing require('esbuild-wasm') with require('esbuild') in lib/util/prepare-test-execution-plan.js. Native esbuild must be installed as a dev dependency alongside artillery. The following script can be run as part of your install/CI setup:

const fs = require('fs'); const path = require('path');

const artilleryFilePath = path.join( __dirname, 'node_modules/artillery/lib/util/prepare-test-execution-plan.js' );

if (!fs.existsSync(artilleryFilePath)) { console.log('[patch-artillery] File not found, skipping patch'); process.exit(0); }

const content = fs.readFileSync(artilleryFilePath, 'utf8');

if (!content.includes("require('esbuild-wasm')")) { console.log('[patch-artillery] Already patched — native esbuild is in use'); process.exit(0); }

fs.writeFileSync( artilleryFilePath, content.replaceAll("require('esbuild-wasm')", "require('esbuild')") ); console.log('[patch-artillery] Patched — replaced esbuild-wasm with native esbuild');

This confirms the native esbuild API is a drop-in replacement and the only change needed is the package name.