From 7c177965676acc259942fd350416a05421c580c6 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 23 Jun 2025 17:03:13 +0200 Subject: [PATCH 1/2] fix(astro): Try-catch `controller.close()` usage --- packages/astro/src/server/middleware.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/astro/src/server/middleware.ts b/packages/astro/src/server/middleware.ts index f339f7b6f979..bb92e6764fa6 100644 --- a/packages/astro/src/server/middleware.ts +++ b/packages/astro/src/server/middleware.ts @@ -194,7 +194,12 @@ async function instrumentRequest( sendErrorToSentry(e); controller.error(e); } finally { - controller.close(); + // try catch this, as it could have been manually closed by a user-land middleware + try { + controller.close(); + } catch { + // we assume this means it was already closed + } } }, }); From 32e798f9fbe3f7bb9d188af00e86ee1ec252683b Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 25 Jun 2025 13:25:42 +0200 Subject: [PATCH 2/2] better handling of errors --- packages/astro/src/server/middleware.ts | 27 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/astro/src/server/middleware.ts b/packages/astro/src/server/middleware.ts index bb92e6764fa6..11fca078a619 100644 --- a/packages/astro/src/server/middleware.ts +++ b/packages/astro/src/server/middleware.ts @@ -184,22 +184,33 @@ async function instrumentRequest( const newResponseStream = new ReadableStream({ start: async controller => { + // Assign to a new variable to avoid TS losing the narrower type checked above. + const body = originalBody; + + async function* bodyReporter(): AsyncGenerator { + try { + for await (const chunk of body) { + yield chunk; + } + } catch (e) { + // Report stream errors coming from user code or Astro rendering. + sendErrorToSentry(e); + throw e; + } + } + + const reportedBody = bodyReporter(); + try { - for await (const chunk of originalBody) { + for await (const chunk of reportedBody) { const html = typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true }); const modifiedHtml = addMetaTagToHead(html); controller.enqueue(new TextEncoder().encode(modifiedHtml)); } } catch (e) { - sendErrorToSentry(e); controller.error(e); } finally { - // try catch this, as it could have been manually closed by a user-land middleware - try { - controller.close(); - } catch { - // we assume this means it was already closed - } + controller.close(); } }, });