diff --git a/extensions/telegram/src/bot/delivery.test.ts b/extensions/telegram/src/bot/delivery.test.ts index 086b1c46a78f..716aa8d0cf29 100644 --- a/extensions/telegram/src/bot/delivery.test.ts +++ b/extensions/telegram/src/bot/delivery.test.ts @@ -218,9 +218,10 @@ function createHtmlParseError(operation = "sendMessage") { ); } -function createWrappedPreConnectHttpError(operation = "sendMessage") { - const root = Object.assign(new Error("getaddrinfo ENOTFOUND api.telegram.org"), { - code: "ENOTFOUND", +function createWrappedConnectTimeoutHttpError(operation = "sendMessage") { + const root = Object.assign(new Error("Connect Timeout Error"), { + name: "ConnectTimeoutError", + code: "UND_ERR_CONNECT_TIMEOUT", }); const fetchError = Object.assign(new TypeError("fetch failed"), { cause: root }); return Object.assign(new Error(`Network request for '${operation}' failed!`), { @@ -1027,12 +1028,12 @@ describe("deliverReplies", () => { expect(runtime.error).toHaveBeenCalledTimes(1); }); - it("retries final text sends for wrapped pre-connect grammY HttpError envelopes", async () => { + it("retries final text sends for wrapped Undici connect timeouts", async () => { vi.useFakeTimers(); const runtime = createRuntime(); const sendMessage = vi .fn() - .mockRejectedValueOnce(createWrappedPreConnectHttpError("sendMessage")) + .mockRejectedValueOnce(createWrappedConnectTimeoutHttpError("sendMessage")) .mockResolvedValueOnce({ message_id: 12, chat: { id: "123" }, diff --git a/extensions/telegram/src/network-errors.test.ts b/extensions/telegram/src/network-errors.test.ts index 8381b081952d..7e3ce9bc5aa7 100644 --- a/extensions/telegram/src/network-errors.test.ts +++ b/extensions/telegram/src/network-errors.test.ts @@ -239,7 +239,7 @@ describe("isSafeToRetrySendError", () => { ["ECONNRESET", "read ECONNRESET", false], ["ETIMEDOUT", "connect ETIMEDOUT", false], ["EPIPE", "write EPIPE", false], - ["UND_ERR_CONNECT_TIMEOUT", "connect timeout", false], + ["UND_ERR_CONNECT_TIMEOUT", "connect timeout", true], ])("returns %s => %s", (code, message, expected) => { expect(isSafeToRetrySendError(errorWithCode(message, code))).toBe(expected); }); diff --git a/extensions/telegram/src/network-errors.ts b/extensions/telegram/src/network-errors.ts index dbcfb08329ea..1c299fc1cf59 100644 --- a/extensions/telegram/src/network-errors.ts +++ b/extensions/telegram/src/network-errors.ts @@ -47,6 +47,7 @@ const PRE_CONNECT_ERROR_CODES = new Set([ "ENETDOWN", // Local network interface is down before connect completes (never sent) "ENETUNREACH", // No route to host (never sent) "EHOSTUNREACH", // Host unreachable (never sent) + "UND_ERR_CONNECT_TIMEOUT", // TCP/TLS connect timeout (request never sent) ]); const RECOVERABLE_ERROR_NAMES = new Set([ diff --git a/extensions/telegram/src/send.test.ts b/extensions/telegram/src/send.test.ts index 7bb87c46edfb..4a60ba7876b9 100644 --- a/extensions/telegram/src/send.test.ts +++ b/extensions/telegram/src/send.test.ts @@ -2401,11 +2401,12 @@ describe("sendMessageTelegram", () => { vi.useRealTimers(); }); - it("retries wrapped pre-connect HttpError sends", async () => { + it("retries wrapped Undici connect timeout sends", async () => { vi.useFakeTimers(); const chatId = "123"; - const root = Object.assign(new Error("connect ECONNREFUSED api.telegram.org"), { - code: "ECONNREFUSED", + const root = Object.assign(new Error("Connect Timeout Error"), { + name: "ConnectTimeoutError", + code: "UND_ERR_CONNECT_TIMEOUT", }); const fetchError = Object.assign(new TypeError("fetch failed"), { cause: root }); const err = Object.assign(new Error("Network request for 'sendMessage' failed!"), {