yikart/AiToEarn · error · AppException

ResponseCode.ConfigEditorPm2Unavailable

ResponseCode.ConfigEditorPm2Unavailable

Error message

ConfigEditorPm2Unavailable

What it means

ConfigRestartService.restart() can only restart the process if it is managed by PM2: it reads process.env['pm_id'], the per-process id PM2 injects. When pm_id is absent the process is not running under PM2 (or the env var was stripped), so restart() throws ConfigEditorPm2Unavailable instead of attempting `pm2 restart`.

Source

Thrown at project/aitoearn-backend/libs/config-editor/src/config-restart.service.ts:12

import { execFile } from 'node:child_process'
import { Injectable, Logger } from '@nestjs/common'
import { AppException, ResponseCode } from '@yikart/common'

@Injectable()
export class ConfigRestartService {
  private readonly logger = new Logger(ConfigRestartService.name)

  restart(): void {
    const pm2ProcessId = process.env['pm_id']
    if (!pm2ProcessId) {
      throw new AppException(ResponseCode.ConfigEditorPm2Unavailable)
    }

    try {
      const child = execFile('pm2', ['restart', pm2ProcessId], (error) => {
        if (error)
          this.logger.error(error)
      })
      child.unref()
    }
    catch (error) {
      throw new AppException(
        ResponseCode.ConfigEditorRestartFailed,
        error instanceof Error ? error.message : String(error),
      )
    }
  }
}

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Run the service under PM2 (`pm2 start ...`) so pm_id is set in the environment
  2. If in Docker, use `pm2-runtime start ecosystem.config.js` as the container entrypoint, or drop the restart feature in favor of container restarts
  3. Verify the env var survives: `console.log(process.env.pm_id)` at startup; if empty, fix how pm2 launches the app
  4. Remove/disable the restart endpoint if the deployment target is systemd/Kubernetes where pm2 restart is meaningless

Example fix

// before (Dockerfile CMD)
CMD ["node", "dist/main.js"]
// after
CMD ["pm2-runtime", "ecosystem.config.js"]
Defensive patterns

Strategy: fallback

Validate before calling

if (!process.env.pm_id)
  throw new Error('Not running under PM2: restart endpoint unavailable')

Type guard

function isPm2Managed(env = process.env): boolean {
  return typeof env.pm_id === 'string' && env.pm_id !== ''
}

Try / catch

try {
  restartService.restart()
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.ConfigEditorPm2Unavailable)
    logger.warn('No pm_id: falling back to external restart (docker restart / manual)')
}

Prevention

When it happens

Trigger: restart() is called (e.g. after saving a config that requires a process restart) while the Node process was started directly (node dist/main.js, nx serve, nodemon, docker CMD without pm2) or inside a container where PM2's env vars are not propagated.

Common situations: Local dev with `pnpm server:serve` where config changes can't hot-restart; Docker containers running the app without pm2-runtime; pm2 started via a wrapper that drops env vars (pm2 with --no-daemon in odd shells, or `pm2 start node --` losing env); a migration from pm2 to systemd/kubernetes where the restart endpoint still exists.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/eb86440f4093b824. Report an issue: GitHub.