From dc9096303c0b6280c600ea1a6410b210fbb70fff Mon Sep 17 00:00:00 2001 From: ILLISIS <92364928+ILLISIS@users.noreply.github.com> Date: Mon, 12 Oct 2026 10:00:01 +1100 Subject: [PATCH] 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 Co-authored-by: Claude Opus 5.5 (1M context) --- packages/host/src/Host.ts | 2 +- test/host/Host.test.js | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/host/src/Host.ts b/packages/host/src/Host.ts index 3ab3bb45..8750aace 100644 --- a/packages/host/src/Host.ts +++ b/packages/host/src/Host.ts @@ -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 ); diff --git a/test/host/Host.test.js b/test/host/Host.test.js index bbfffc58..36a7c0f6 100644 --- a/test/host/Host.test.js +++ b/test/host/Host.test.js @@ -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 });