Skip to content

Commit fe1a22c

Browse files
authored
fix(browser): Handle case where fetch can be undefined (#5973)
Some users reported cases where the `nativeFetch` call was returning undefined. I have no idea how this happens, but in order for us to not send unnecessary errors to Sentry, let's be a little defensive in the usage of fetch.
1 parent ac03a39 commit fe1a22c

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

packages/browser/src/transports/fetch.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { createTransport } from '@sentry/core';
22
import { Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/types';
3+
import { rejectedSyncPromise } from '@sentry/utils';
34

45
import { BrowserTransportOptions } from './types';
5-
import { FetchImpl, getNativeFetchImplementation } from './utils';
6+
import { clearCachedFetchImplementation, FetchImpl, getNativeFetchImplementation } from './utils';
67

78
/**
89
* Creates a Transport that uses the Fetch API to send events to Sentry.
@@ -30,13 +31,18 @@ export function makeFetchTransport(
3031
...options.fetchOptions,
3132
};
3233

33-
return nativeFetch(options.url, requestOptions).then(response => ({
34-
statusCode: response.status,
35-
headers: {
36-
'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
37-
'retry-after': response.headers.get('Retry-After'),
38-
},
39-
}));
34+
try {
35+
return nativeFetch(options.url, requestOptions).then(response => ({
36+
statusCode: response.status,
37+
headers: {
38+
'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
39+
'retry-after': response.headers.get('Retry-After'),
40+
},
41+
}));
42+
} catch (e) {
43+
clearCachedFetchImplementation();
44+
return rejectedSyncPromise(e);
45+
}
4046
}
4147

4248
return createTransport(options, makeRequest);

packages/browser/src/transports/utils.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { isNativeFetch, logger } from '@sentry/utils';
22

33
import { WINDOW } from '../helpers';
44

5-
let cachedFetchImpl: FetchImpl;
5+
let cachedFetchImpl: FetchImpl | undefined = undefined;
66

77
export type FetchImpl = typeof fetch;
88

@@ -78,3 +78,8 @@ export function getNativeFetchImplementation(): FetchImpl {
7878
return (cachedFetchImpl = fetchImpl.bind(WINDOW));
7979
/* eslint-enable @typescript-eslint/unbound-method */
8080
}
81+
82+
/** Clears cached fetch impl */
83+
export function clearCachedFetchImplementation(): void {
84+
cachedFetchImpl = undefined;
85+
}

packages/browser/test/unit/transports/fetch.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,13 @@ describe('NewFetchTransport', () => {
9898
...REQUEST_OPTIONS,
9999
});
100100
});
101+
102+
it('handles when `getNativeFetchImplementation` is undefined', async () => {
103+
const mockFetch = jest.fn(() => undefined) as unknown as FetchImpl;
104+
const transport = makeFetchTransport(DEFAULT_FETCH_TRANSPORT_OPTIONS, mockFetch);
105+
106+
expect(mockFetch).toHaveBeenCalledTimes(0);
107+
await expect(() => transport.send(ERROR_ENVELOPE)).not.toThrow();
108+
expect(mockFetch).toHaveBeenCalledTimes(1);
109+
});
101110
});

0 commit comments

Comments
 (0)