diff --git a/packages/node/src/transports/http.ts b/packages/node/src/transports/http.ts index 687325b776f4..4bc5c696e05a 100644 --- a/packages/node/src/transports/http.ts +++ b/packages/node/src/transports/http.ts @@ -47,7 +47,18 @@ function streamFromBody(body: Uint8Array | string): Readable { * Creates a Transport that uses native the native 'http' and 'https' modules to send events to Sentry. */ export function makeNodeTransport(options: NodeTransportOptions): Transport { - const urlSegments = new URL(options.url); + let urlSegments: URL; + + try { + urlSegments = new URL(options.url); + } catch (e) { + // eslint-disable-next-line no-console + console.warn( + '[@sentry/node]: Invalid dsn or tunnel option, will not send any events. The tunnel option must be a full URL when used.', + ); + return createTransport(options, () => Promise.resolve({})); + } + const isHttps = urlSegments.protocol === 'https:'; // Proxy prioritization: http => `options.proxy` | `process.env.http_proxy` diff --git a/packages/node/test/transports/http.test.ts b/packages/node/test/transports/http.test.ts index 9594940c2014..0bf61118b9e9 100644 --- a/packages/node/test/transports/http.test.ts +++ b/packages/node/test/transports/http.test.ts @@ -399,4 +399,20 @@ describe('makeNewHttpTransport()', () => { ); }); }); + + it('should create a noop transport if an invalid url is passed', async () => { + const requestSpy = jest.spyOn(http, 'request'); + const transport = makeNodeTransport({ ...defaultOptions, url: 'foo' }); + await transport.send(EVENT_ENVELOPE); + expect(requestSpy).not.toHaveBeenCalled(); + }); + + it('should warn if an invalid url is passed', async () => { + const consoleWarnSpy = jest.spyOn(console, 'warn'); + const transport = makeNodeTransport({ ...defaultOptions, url: 'invalid url' }); + await transport.send(EVENT_ENVELOPE); + expect(consoleWarnSpy).toHaveBeenCalledWith( + '[@sentry/node]: Invalid dsn or tunnel option, will not send any events. The tunnel option must be a full URL when used.', + ); + }); });