Log the message of an instance start error without a stack (#1066)

HostRouter.wakeInstance() logged err.stack, which RequestError leaves
undefined, so a failed start was logged as "Error starting instance:
undefined" and the reason, such as no game port left in the range, was
lost.


Claude-Session: https://claude.ai/code/session_01F7obMEi4L4PzUQ8w8q9Uyz

Co-authored-by: ILLISIS <jayson.harris01@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-10-12 00:00:01 +01:00
1 parent ae6e25d1b9
commit dc9096303c
2 files changed
+30 -2

No files matched your search

+1 -1
View File
@@ -218,7 +218,7 @@ export class HostRouter {
this.host._connectInstance(dst.id).then(instanceConnection => {
instanceConnection.connector.forward(message);
}).catch(err => {
logger.error(`Error starting instance:\n${err.stack}`, this.host.instanceLogMeta(dst.id));
logger.error(`Error starting instance:\n${err.stack ?? err.message}`, this.host.instanceLogMeta(dst.id));
origin.connector.sendResponseError(
new lib.ResponseError(err.message, err.code, err.stack), message.src
);
+29 -1
View File
@@ -4,7 +4,7 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import * as lib from "@clusterio/lib";
import Host, { _discoverInstances } from "@clusterio/host/dist/node/src/Host.js";
import Host, { _discoverInstances, HostRouter } from "@clusterio/host/dist/node/src/Host.js";
import Instance from "@clusterio/host/dist/node/src/Instance.js";
import { HostConnector } from "@clusterio/host/dist/node/host.js";
import "../setup_logging.js";
@@ -31,6 +31,34 @@ describe("host/src/Host", function() {
});
});
describe("class HostRouter", function() {
describe(".wakeInstance()", function() {
it("should log the message of a start error that has no stack", async function() {
// RequestError leaves its stack undefined
const err = new lib.RequestError("No available port left to assign from host.factorio_port_range");
const mockHost = {
_shuttingDown: false,
_connectInstance: async () => { throw err; },
instanceLogMeta: () => ({}),
};
const responses = [];
const origin = { connector: { sendResponseError: response => responses.push(response) } };
const message = { dst: lib.Address.fromShorthand({ instanceId: 1 }) };
const logged = [];
const originalError = lib.logger.error;
lib.logger.error = text => { logged.push(text); };
try {
new HostRouter(mockHost).wakeInstance(origin, message);
await new Promise(resolve => setImmediate(resolve));
} finally {
lib.logger.error = originalError;
}
assert.equal(responses.length, 1);
assert.equal(logged.length, 1);
assert.match(logged[0], /No available port left to assign/);
});
});
});
describe("class Host", function() {
describe(".handleSyncUserListsEvent()", function() {
const hostAddress = lib.Address.fromShorthand({ hostId: 1 });