mihomo-party-org/clash-party · critical
Core PID ${proc.pid ?? 'unknown'} is still running after SIG
Error message
Core PID ${proc.pid ?? 'unknown'} is still running after SIGKILL What it means
This error is thrown in the core stop path (src/main/core/manager.ts:875) after SIGINT failed to stop the core process and a follow-up SIGKILL also failed: waitForExit() still reports the child running. The library throws because it cannot guarantee the previous core process is dead, which would make a subsequent start unreliable (port conflicts, stale state).
Source
Thrown at src/main/core/manager.ts:875
setStopCoreBeforeAdminRestart(stopCore)
async function ensureCoreProcessExited(proc: ChildProcess | null): Promise<void> {
if (!proc) return
const waitForExit = async (): Promise<boolean> => {
const deadline = Date.now() + coreShutdownTimeout
while (proc.exitCode === null && proc.signalCode === null && Date.now() < deadline) {
await delay(50)
}
return proc.exitCode !== null || proc.signalCode !== null
}
if (await waitForExit()) return
managerLogger.warn(`Core PID ${proc.pid ?? 'unknown'} did not exit after SIGINT; sending SIGKILL`)
proc.kill('SIGKILL')
if (!(await waitForExit())) {
throw new Error(`Core PID ${proc.pid ?? 'unknown'} is still running after SIGKILL`)
}
}
async function restartCoreOnce(forceStop: boolean): Promise<void> {
const startAttempt = await runCoreOperation(async () => {
const previousChild = child
await stopCoreInternal(forceStop)
if (process.platform === 'darwin') await ensureCoreProcessExited(previousChild)
return startCoreInternal(false, true)
})
await startAttempt.readiness
}
function trackCoreRestart(operation: () => Promise<void>): Promise<void> {
if (pendingRestart) return pendingRestart
isRestarting = true
const restart = operation().finally(() => {View on GitHub (pinned to 911e090537)
Solutions
- Investigate why the core ignores SIGKILL: check process state (ps/proc), permissions, containers, or I/O hangs
- Increase the waitForExit timeout if exits are merely slow
- Escalate externally (kill -9 on the host, container restart) and verify the port is free before restarting the core
- Report/log the stuck PID for diagnosis rather than silently starting a new core over the old one
Example fix
// before
if (!(await waitForExit())) {
throw new Error(`Core PID ${proc.pid ?? 'unknown'} is still running after SIGKILL`)
}
// after
if (!(await waitForExit())) {
managerLogger.error(`Core PID ${proc.pid ?? 'unknown'} unkillable; state=${proc.signalCode}`)
throw new CoreProcessUnkillableError(proc.pid)
} Defensive patterns
Strategy: retry
Validate before calling
const stale = await isPidAlive(proc.pid)
if (stale) {
await killProcessTree(proc.pid, { force: true })
await waitForPortFree(corePort)
} Try / catch
try {
await stopCore()
} catch (err) {
if (err.message.includes('still running after SIGKILL')) {
await escalateExternalKill(proc.pid)
await waitForPortFree(corePort)
await startCore()
} else throw err
} Prevention
- Monitor core process health so hangs are detected before stop
- Verify the core port is free before restarting after a failed kill
- Run the core with adequate permissions (not in a restricted container that blocks signals)
- Keep the stop timeout generous enough for slow exits
When it happens
Trigger: stopCoreInternal sends SIGINT, the core ignores it, SIGKILL is sent, and waitForExit() still finds the PID alive after the timeout — typically a stuck or zombie child, PID reuse, or a process in uninterruptible kernel state (D state).
Common situations: Core binary hung on I/O or a dead lock making it un-killable; container/permission issues where SIGKILL cannot reach the process; PID reused by another process; extremely slow exit exceeding the wait timeout.
Related errors
- Core startup is unavailable because startup safety checks di
- Core startup was cancelled because the application is shutti
- Login timed out
- Core PID ${proc.pid ?? 'unknown'} did not exit after SIGINT;
- Core not ready after ${CORE_READY_MAX_RETRIES} attempts, pro
AI-assisted analysis of mihomo-party-org/clash-party@911e090537 (2026-08-30).
Data as JSON: /api/errors/628b59ca55b4c64b.
Report an issue: GitHub.