-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
PM2 is polluting the environment variables of spawned subprocesses by passing object properties that get stringified to "[object Object]"
All spawned processes receive corrupted environment variables like env="[object Object]", axm_monitor="[object Object]", etc.
Environment
- PM2 Version: (6.0.14)
- Node.js Version: (v24.11.1)
- Operating System: (affects all platforms)
- Interpreter: All interpreters (Node.js, Python, Ruby, PHP, etc.)
Steps to Reproduce
- Create a Node.js script (
test.js):
console.log("env variable:", process.env.env);
console.log("axm_monitor:", process.env.axm_monitor);
console.log("Type of env:", typeof process.env.env);- Create a PM2 config (
ecosystem.config.js):
module.exports = {
apps: [{
name: "test-node",
script: "./test.js",
interpreter: "node",
env: {
MY_VAR: "hello"
}
}]
};- Run with PM2:
pm2 start ecosystem.config.js
pm2 logs test-nodeOutput:
env variable: [object Object]
axm_monitor: [object Object]
Type of env: string
Root Cause Analysis
The Flow
- User config contains
env: { MY_VAR: "hello" }as an object God.executeApp()(lib/God.js:178) calls:
`ALL interpreters affected**: Node.js, Python, Ruby, PHP, etc. all receive corrupted environment variables
- Environment variable name collision: If a user actually needs an env var named
env, it's overwritten with"[object Object]" - Debugging confusion: Users see mysterious
[object Object]values in their applications - Silent data corruption: Applications may silently fail or behave incorrectly when checking for these environment variables
-
PM2 adds metadata objects (lib/God.js:183-186):
env_copy['axm_actions'] = []; env_copy['axm_monitor'] = {}; env_copy['axm_options'] = {}; env_copy['axm_dynamic'] = {};
-
ForkMode.forkMode()(lib/God/ForkMode.js:97) passes the entirepm2_envtospawn():var options = { env: pm2_env, // Contains nested objects! detached: true, cwd: pm2_env.pm_cwd, stdio: ['pipe', 'pipe', 'pipe', 'ipc'] } spawn(command, args, options);
-
Node.js
spawn()calls.toString()on all values in theenvobject -
Objects become
"[object Object]"when stringified
The 6 Polluted Environment Variables
env- The original config env object (still present after spreading)axm_monitor- PM2 metrics objectaxm_options- PM2 monitoring optionsaxm_dynamic- PM2 dynamic configurationaxm_actions- PM2 actions arraynode_args- Node arguments array
Impact
- Interpreters receive corrupted environment variables
- Environment variable name collision: If a user actually needs an env var named
env, it's overwritten with"[object Object]" - Debugging confusion: Users see mysterious
[object Object]values in their applications
Proposed Solutions
Solution 1: Clean up objects after spreading (Minimal change)
In lib/God.js after line 178:
Utility.extend(env_copy, env_copy.env);
// Remove object properties that shouldn't be environment variables
delete env_copy.env;
// Note: axm_* objects are added later but should also be filtered before spawnThen in lib/God/ForkMode.js before spawn:
// Create clean environment with only primitive values
var spawnEnv = {};
for (var key in pm2_env) {
var type = typeof pm2_env[key];
if (type === 'string' || type === 'number' || type === 'boolean') {
spawnEnv[key] = String(pm2_env[key]);
}
}
var options = {
env: spawnEnv, // Only primitives
detached: true,
cwd: pm2_env.pm_cwd,
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
}Solution 2: Separate pm2_env from spawn env (Better design)
Store PM2 metadata separately and only pass actual environment variables to spawn:
// In God.js, separate concerns
var pm2_metadata = {
axm_monitor: {},
axm_options: {},
axm_dynamic: {},
axm_actions: []
};
// Keep env_copy clean for spawn
// Store metadata in process object separatelyWorkaround
There's currently no clean workaround except to:
- Avoid using environment variable names that conflict with PM2's internal objects (
env,axm_monitor,axm_options,axm_dynamic,axm_actions,node_args) - Filter out
"[object Object]"values in your application code - Check if an environment variable equals
"[object Object]"before using it
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels