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
- Run the service under PM2 (`pm2 start ...`) so pm_id is set in the environment
- If in Docker, use `pm2-runtime start ecosystem.config.js` as the container entrypoint, or drop the restart feature in favor of container restarts
- Verify the env var survives: `console.log(process.env.pm_id)` at startup; if empty, fix how pm2 launches the app
- 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
- Run production services via pm2 or pm2-runtime so pm_id exists
- In containers, prefer container-native restarts and hide the pm2 restart endpoint
- Verify pm_id at startup with a health check
- Do not strip PM2_* env vars with custom env sanitization
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.