diff --git a/lib/internal/quic/quic.js b/lib/internal/quic/quic.js index 632369fc908..b670606e71f 100644 --- a/lib/internal/quic/quic.js +++ b/lib/internal/quic/quic.js @@ -1375,14 +1375,21 @@ function configureOutbound(handle, stream, body) { // Handle Promise - await and recurse. Native promises auto-flatten, // so the resolved value will never itself be a promise. if (isPromise(body)) { + const onError = (err) => { + if (!stream.destroyed) { + stream.destroy(err); + } + }; PromisePrototypeThen( body, - (resolved) => configureOutbound(handle, stream, resolved), - (err) => { - if (!stream.destroyed) { - stream.destroy(err); + (resolved) => { + try { + configureOutbound(handle, stream, resolved); + } catch (err) { + onError(err); } }, + onError, ); return; } diff --git a/test/parallel/test-quic-stream-body-promise-invalid.mjs b/test/parallel/test-quic-stream-body-promise-invalid.mjs new file mode 100644 index 00000000000..65f4dd27bb3 --- /dev/null +++ b/test/parallel/test-quic-stream-body-promise-invalid.mjs @@ -0,0 +1,39 @@ +// Flags: --experimental-quic --no-warnings + +// Test: body: Promise resolving to an invalid body destroys the stream. +// When the body is a Promise that resolves to an unsupported type, the +// stream should be destroyed with the same ERR_INVALID_ARG_TYPE that +// setBody() throws synchronously for that type. + +import { hasQuic, skip, mustCall } from '../common/index.mjs'; +import assert from 'node:assert'; + +if (!hasQuic) { + skip('QUIC is not enabled'); +} + +const { listen, connect } = await import('../common/quic.mjs'); + +const serverEndpoint = await listen(mustCall(async (serverSession) => { + await serverSession.closed; +}), { transportParams: { maxIdleTimeout: 5 } }); + +const clientSession = await connect(serverEndpoint.address, { + transportParams: { maxIdleTimeout: 5 }, +}); +await clientSession.opened; + +const stream = await clientSession.createBidirectionalStream(); + +assert.throws(() => stream.setBody(42), { code: 'ERR_INVALID_ARG_TYPE' }); + +const stream2 = await clientSession.createBidirectionalStream(); + +const closedPromise = assert.rejects(stream2.closed, { + code: 'ERR_INVALID_ARG_TYPE', +}); + +stream2.setBody(Promise.resolve(42)); + +await Promise.all([closedPromise, clientSession.closed]); +await serverEndpoint.close();