louislam/uptime-kuma · error · Error

PM2 process '${processName}' is ${entry.status}.

Error message

PM2 process '${processName}' is ${entry.status}.

What it means

The lookup succeeded (an entry was found by name or id) but entry.status !== 'online'. PM2 exposes statuses such as stopped, errored, stopped, launching, etc. The monitor only treats 'online' as healthy, so any other status is surfaced verbatim in the interpolated message and re-thrown to mark the heartbeat DOWN.

Source

Thrown at server/monitor-types/pm2.js:30

     * @param {object} heartbeat The heartbeat object to update.
     * @returns {Promise<void>}
     */
    async check(monitor, heartbeat) {
        const processName = (monitor.system_service_name || "").trim();
        const processList = await getPM2ProcessList();
        const entry = processList.find((item) => item.name === processName || item.id === processName);

        if (!entry) {
            throw new Error(`PM2 process '${processName}' was not found.`);
        }

        if (entry.status === "online") {
            heartbeat.status = UP;
            heartbeat.msg = `PM2 process '${processName}' is online.`;
            return;
        }

        throw new Error(`PM2 process '${processName}' is ${entry.status}.`);
    }
}

module.exports = {
    PM2MonitorType,
};

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Inspect with `pm2 describe <name>` to see why it is not online.
  2. Restart with `pm2 restart <name>` and, for persistence, `pm2 save` plus `pm2 startup`.
  3. If status is 'errored', read `pm2 logs <name> --err` for the crash cause and fix the application.
  4. If 'launching' lingers, raise PM2's wait_ready/expire settings or check the app's startup.

Example fix

# before
pm2 stop my-app
# after
pm2 restart my-app && pm2 save
Defensive patterns

Strategy: try-catch

Validate before calling

async function assertPm2Online(name) {
  const list = await getPM2ProcessList();
  const entry = list.find(p => p.name === name || p.id === name);
  if (!entry) throw new Error(`PM2 process '${name}' was not found.`);
  if (entry.status !== 'online') {
    throw new Error(`PM2 process '${name}' is ${entry.status}.`);
  }
}

Type guard

function isPm2Online(entry) {
  return !!entry && entry.status === 'online';
}

Try / catch

try {
  await pm2Monitor.check(monitor, heartbeat);
} catch (e) {
  if (/is \w+\.$/.test(e.message)) {  // 'is stopped.', 'is errored.'
    heartbeat.status = DOWN;
    heartbeat.msg = e.message;     // keep the PM2 status for the UI
  }
}

Prevention

When it happens

Trigger: PM2 reports the process in any non-online state: stopped (`pm2 stop`), errored (crashed and exhausted restarts), launching, or one of PM2's transient states. The entry exists in the list, so the !entry check passes and execution falls through to the throw at pm2.js:30.

Common situations: Process crashed and PM2 left it in 'errored', a manual `pm2 stop`, PM2 still launching after a host restart, or --no-autorestart leaving it stopped after a crash.

Related errors


AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12). Data as JSON: /api/errors/5abc66a1fb059239. Report an issue: GitHub.