can1357/oh-my-pi · error · Error
Port ${port} is in use, but the listening process could not
Error message
Port ${port} is in use, but the listening process could not be identified. What it means
reclaimStatsPort() calls findPortHolder() to map the port to a owning process. When the port is reported in use but findPortHolder() returns null — no owning process could be identified from the OS tooling — this error is thrown rather than killing an unknown target. It is a deliberate safety stop: without a PID/image the code will not attempt termination.
Source
Thrown at packages/stats/src/port-conflict.ts:224
} catch (error) {
if (error instanceof Error && "code" in error && error.code === "ESRCH") return;
throw new Error(`Failed to inspect ${holder.image} (PID ${holder.pid})`, { cause: error });
}
}
try {
process.kill(holder.pid, "SIGKILL");
} catch (error) {
if (error instanceof Error && "code" in error && error.code === "ESRCH") return;
throw new Error(`Failed to kill ${holder.image} (PID ${holder.pid})`, { cause: error });
}
await Bun.sleep(PROCESS_EXIT_POLL_MS);
}
async function reclaimStatsPort(port: number): Promise<"retry"> {
const holder = await findPortHolder(port);
if (!holder) {
throw new Error(`Port ${port} is in use, but the listening process could not be identified.`);
}
if (holder.pid === process.pid) {
throw new Error(`Port ${port} is held by the current process (${holder.image}, PID ${holder.pid}).`);
}
const normalizedImage = holder.image
.toLowerCase()
.replace(/\.exe$/, "")
.replace(/ \(deleted\)$/, "");
const normalizedCommand = holder.commandLine.toLowerCase().replaceAll("\\", "/");
const hasStatsIdentity =
normalizedImage === "omp-stats" ||
/(?:^|[/"'\s])omp-stats(?:\.exe)?(?:["'\s]|$)/.test(normalizedCommand) ||
/\/packages\/stats\/src\/index\.ts(?:["'\s]|$)/.test(normalizedCommand) ||
(normalizedImage === "omp" && /(?:^|\s)stats(?:\s|$)/.test(normalizedCommand)) ||
/(?:^|\/)omp(?:\.exe)?["'\s]+stats(?:["'\s]|$)/.test(normalizedCommand);
if (!STATS_RUNTIME_IMAGES[normalizedImage] || !hasStatsIdentity) {
throw new Error(View on GitHub (pinned to 9690622007)
Solutions
- Install or expose the process-listing tooling the environment needs (lsof/ss) so the holder can be identified
- Wait a moment and retry — the holder may have exited between checks
- Free the port manually (netstat -ano / lsof -i :<port>, then kill the PID) and restart the stats server
- Configure the stats server to use a different port
Example fix
// before
await prepareStatsPort(port); // throws when holder unidentifiable
// after
try {
await prepareStatsPort(port);
} catch (err) {
if (err.message.includes('could not be identified')) {
await Bun.sleep(1000);
await prepareStatsPort(port); // holder may have exited; or pick another port
} else throw err;
} Defensive patterns
Strategy: retry
Validate before calling
const busy = await isPortInUse(port);
const holder = busy ? await findPortHolder(port) : null;
if (busy && !holder) console.warn(`Port ${port} busy but owner unidentified — resolve manually before starting stats`); Try / catch
try {
await prepareStatsPort(port);
} catch (err) {
if (err.message.includes('could not be identified')) {
await Bun.sleep(1500);
await prepareStatsPort(port); // holder may have exited; else pick another port
} else throw err;
} Prevention
- Install lsof/ss (or Windows equivalents) so port owners can be identified
- Retry briefly on startup — transient TIME_WAIT races resolve themselves
- Fall back to an alternate port instead of blocking startup
- Free unidentifiable sockets manually via netstat/lsof before launching
When it happens
Trigger: Port is occupied (bind/listen fails) but findPortHolder() cannot resolve an owner — e.g. lsof/ss output unavailable or empty for that port, a foreign-namespace socket, or a race where the holder exited between the bind attempt and the lookup.
Common situations: Minimal containers or Windows environments lacking lsof/netstat equivalents the lookup relies on; a socket held by a kernel service; the port just released but still in TIME_WAIT while a probe still reports it busy.
Related errors
- Port ${port} is in use by ${holder.image} (PID ${holder.pid}
- timed out: {command}
- V2 remote compaction failed (${response.status} ${response.s
- V2 compaction stream closed before response.completed
- Auth broker response failed schema validation
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/93ff5bdea7d69705.
Report an issue: GitHub.