MagicMirrorOrg/MagicMirror · warning
Port still not available after attempts
Error message
Port ${port} still not available after ${maxAttempts} attempts What it means
serveronly/watcher.js restarts the server process and calls waitForPort to detect when the port is free again. It polls isPortAvailable up to maxAttempts times at PORT_CHECK_INTERVAL_MS; if the port is still occupied after all attempts, this warning is logged, meaning the server restart may fail or the old process is still holding the port.
Solutions
- Find and kill the process holding the port: `lsof -i :8080` / `ss -ltnp | grep 8080`, then kill it.
- Wait a moment and restart serveronly manually to see if the port frees up.
- Increase PORT_CHECK_INTERVAL_MS / maxAttempts in watcher.js if restarts are regularly slow in your environment.
- If inside Docker, ensure the server receives and honors SIGTERM (e.g. use `node serveronly` with init/tini) so children exit cleanly.
Example fix
// shell $ lsof -t -i :8080 | xargs -r kill $ node serveronly/index.js # restart with port now free
Defensive patterns
Strategy: retry
Validate before calling
// before restarting, confirm the port is free:
const net = require("net");
const s = net.createServer();
s.once("error", () => console.error("Port 8080 still in use"));
s.once("listening", () => { console.log("Port free"); s.close(); });
s.listen(8080); Try / catch
try {
await restartServer();
} catch (err) {
if (/still not available/.test(String(err))) {
await new Promise((r) => setTimeout(r, 2000));
await restartServer(); // retry after the old process exits
} else {
throw err;
}
} Prevention
- Kill stale MagicMirror processes before starting serveronly
- Avoid saving many files in rapid succession when the watcher restarts the server
- Run long-lived servers under a supervisor (systemd/tini) so children exit cleanly
- Increase the watcher's polling attempts/interval for slow environments
When it happens
Trigger: File-change-triggered restart where the previous server process hasn't released the port within the polling window; another process bound to the same port; a hung/stuck server child that never exits.
Common situations: Rapid successive file saves triggering overlapping restarts; a zombie MagicMirror process from a crashed earlier run still listening on 8080; running under Docker where the old child ignores SIGTERM.
AI-assisted analysis of MagicMirrorOrg/MagicMirror@4b4a59534f (2026-08-31).
Data as JSON: /api/errors/097c5dbb8ca4d7d1.
Report an issue: GitHub.
Appendix: source
Thrown at serveronly/watcher.js:83
server.listen(port, address);
});
}
/**
* Wait until port is available
* @param {number} port The port to wait for
* @param {number} maxAttempts Maximum number of attempts
* @returns {Promise<void>}
*/
async function waitForPort (port, maxAttempts = PORT_CHECK_MAX_ATTEMPTS) {
for (let i = 0; i < maxAttempts; i++) {
if (await isPortAvailable(port)) {
Log.info(`Port ${port} is now available`);
return;
}
await new Promise((resolve) => setTimeout(resolve, PORT_CHECK_INTERVAL_MS));
}
Log.warn(`Port ${port} still not available after ${maxAttempts} attempts`);
}
/**
* Start the server process
*/
function startServer () {
// Start node directly instead of via npm to avoid process tree issues
child = spawn("node", ["./serveronly"], {
stdio: "inherit",
cwd: path.join(__dirname, "..")
});
child.on("error", (error) => {
Log.error("Failed to start server process:", error.message);
child = null;
});
child.on("exit", (code, signal) => {View on GitHub (pinned to 4b4a59534f)