launchdarkly / js-client-sdk

LaunchDarkly Client-side SDK for Browser JavaScript
Other
109 stars 62 forks source link

Unhandled Exception occurs when there is a network error #283

Closed lukeapage closed 7 months ago

lukeapage commented 1 year ago

Describe the bug We get unhandled exceptions in production that originate from the launch darkly sdk.

We aim to eliminate unhandled exceptions and fix any occurring in our own code, so having them reported from libraries leads to false positives that are hard to filter out.

I believe its simple - there is a synchnonous xhr and because it is synchronous it can throw if there is a network error and you don't have a try catch around it to handle the issue.

Related: https://github.com/launchdarkly/js-client-sdk/issues/147 Related: https://github.com/launchdarkly/react-client-sdk/issues/106 (I think this is more likely the cause of 106 than 147)

Stack Trace

        Source: httpRequest.js
        Name: send
        Line: 34
        Column: 8
********************************************************************************
Line 00031:     }
Line 00032:   }
Line 00033:   if (pageIsClosing) {
Line 00034:     xhr.send(body); // We specified synchronous mode when we called xhr.open
-------------------^
Line 00035:     return emptyResult; // Again, we never want a request to be retried in this case, so we must say it succeeded.
Line 00036:   } else {
Line 00037:     let cancelled;
********************************************************************************

        Source: httpRequest.js
        Name: send
        Line: 34
        Column: 8
********************************************************************************
Line 00031:     }
Line 00032:   }
Line 00033:   if (pageIsClosing) {
Line 00034:     xhr.send(body); // We specified synchronous mode when we called xhr.open
-------------------^
Line 00035:     return emptyResult; // Again, we never want a request to be retried in this case, so we must say it succeeded.
Line 00036:   } else {
Line 00037:     let cancelled;
********************************************************************************

        Source: node_modules/launchdarkly-js-sdk-common/src/EventSender.js
        Name: httpRequest
        Line: 37
        Column: 9
********************************************************************************
Line 00034:             'X-LaunchDarkly-Payload-ID': payloadId,
Line 00035:           });
Line 00036:       return platform
Line 00037:         .httpRequest('POST', url, transformHeaders(headers, options), jsonBody)
--------------------^
Line 00038:         .promise.then(result => {
Line 00039:           if (!result) {
Line 00040:             // This was a response from a fire-and-forget request, so we won't have a status.
********************************************************************************

        Source: node_modules/launchdarkly-js-sdk-common/src/EventSender.js
        Name: null
        Line: 58
        Column: 13
********************************************************************************
Line 00055:     }
Line 00056:
Line 00057:     if (usePost) {
Line 00058:       return doPostRequest(true).catch(() => {});
------------------------^
Line 00059:     } else {
Line 00060:       httpFallbackPing && httpFallbackPing(url + imageUrlPath + '?d=' + utils.base64URLEncode(jsonBody));
Line 00061:       return Promise.resolve(); // we don't wait for this request to complete, it's just a one-way ping
********************************************************************************

        Source: node_modules/launchdarkly-js-sdk-common/src/EventSender.js
        Name: sendChunk
        Line: 79
        Column: 26
********************************************************************************
Line 00076:     }
Line 00077:     const results = [];
Line 00078:     for (let i = 0; i < chunks.length; i++) {
Line 00079:       results.push(sender.sendChunk(chunks[i], url, isDiagnostic, canPost));
-------------------------------------^
Line 00080:     }
Line 00081:     return Promise.all(results);
Line 00082:   };
********************************************************************************

        Source: node_modules/launchdarkly-js-sdk-common/src/EventProcessor.js
        Name: sendEvents
        Line: 138
        Column: 23
********************************************************************************
Line 00135:     }
Line 00136:     queue = [];
Line 00137:     logger.debug(messages.debugPostingEvents(eventsToSend.length));
Line 00138:     return eventSender.sendEvents(eventsToSend, mainEventsUrl).then(responses => {
----------------------------------^
Line 00139:       const responseInfo = responses && responses[0];
Line 00140:       if (responseInfo) {
Line 00141:         if (responseInfo.serverTime) {
********************************************************************************

        Source: node_modules/launchdarkly-js-sdk-common/src/index.js
        Name: flush
        Line: 295
        Column: 57
********************************************************************************
Line 00292:   }
Line 00293:
Line 00294:   function flush(onDone) {
Line 00295:     return utils.wrapPromiseCallback(sendEvents ? events.flush() : Promise.resolve(), onDone);
--------------------------------------------------------------------^
Line 00296:   }
Line 00297:
Line 00298:   function variation(key, defaultValue) {
********************************************************************************

        Source: src/index.js
        Name: flush
        Line: 50
        Column: 11
********************************************************************************
Line 00047:     // are we should attempt to use them. This increases the chance of the events
Line 00048:     // being delivered.
Line 00049:     platform.synchronousFlush = true;
Line 00050:     client.flush().catch(() => {});
----------------------^
Line 00051:     platform.synchronousFlush = false;
Line 00052:   };
Line 00053:
********************************************************************************

        Source: src/index.js
        Name: u
        Line: 66
        Column: 6
********************************************************************************
Line 00063:   //
Line 00064:   const handleVisibilityChange = () => {
Line 00065:     if (document.visibilityState === 'hidden') {
Line 00066:       syncFlush();
-----------------^
Line 00067:     }
Line 00068:   };
Line 00069:
********************************************************************************

Expected behavior Please catch the error and handle it. Feel free to emit a error event etc.

SDK version 3.1.2

kinyoklion commented 1 year ago

Hello @lukeapage,

Thank you for reporting this.

Filed internally as 204871

Thank you, Ryan

NateDawg90 commented 1 year ago

We are also seeing a bunch of these uncaught network errors reported to our Sentry (React Client SDK). A fix would be greatly appreciated! Screenshot 2023-05-31 at 10 56 44 AM

lukeapage commented 10 months ago

Hi,

any plan to fix this @kinyoklion ?

yusinto commented 10 months ago

We just released 3.1.4 which should fix this issue. Thank you for your patience.

DerZyklop commented 8 months ago

Tested it. It is solved for me. I believe this issue should be closed.