question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Test runner hangs with RangeError: Maximum call stack size exceeded

See original GitHub issue

Current behavior:

The following can be experienced when running cypress headlessly on a particular error.

RangeError: Maximum call stack size exceeded
    at _hasBinary (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/socket/node_modules/has-binary/index.js:25:22)
    at _hasBinary (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/socket/node_modules/has-binary/index.js:49:63)
    at _hasBinary (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/socket/node_modules/has-binary/index.js:49:63)
    ...
    at hasBinary (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/socket/node_modules/has-binary/index.js:58:10)
    at /root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/socket/node_modules/socket.io/lib/socket.js:373:16
    at /root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/lib/socket.js:312:22
    at tryCatcher (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/promise.js:510:31)
    at Promise._settlePromise (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/promise.js:567:18)
    at Promise._settlePromise0 (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/promise.js:612:10)
    at Promise._settlePromises (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/promise.js:687:18)
    at Async._drainQueue (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:789:20)
    at tryOnImmediate (timers.js:751:5)
    at processImmediate [as _immediateCallback] (timers.js:722:5)

This effectively hangs the process.

Desired behavior:

This should not happen.

Steps to reproduce: (app code and test code)

It is consistent in our test suite, but it seems that giving a minimally reproducible case is not easy, as merely changing the order of tests will not yield this error.

That said, tracing back the issue, here is what has been found:

The library request-promise-core on error throws the following Error object on a particular error (in our case ECONNREFUSED).

    { 
       name: 'RequestError',
       stack: 'RequestError: Error: connect ECONNREFUSED 0.0.0.0:443\n\
           at new RequestError (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/request-promise-core/lib/errors.js:14:15)\n\
           at Request.plumbing.callback (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/request-promise-core/lib/plumbing.js:87:29)\n\
           at Request.RP$callback [as _callback] (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/request-promise-core/lib/plumbing.js:46:31)\n\
           at self.callback (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/request/request.js:185:22)\n\
           at emitOne (events.js:116:13)\n\
           at Request.emit (events.js:211:7)\n\
           at Request.onRequestError (/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server/node_modules/request/request.js:884:8)\n\
           at emitOne (events.js:121:20)\n\
           at ClientRequest.emit (events.js:211:7)\n\
           at TLSSocket.socketErrorListener (_http_client.js:387:9)\n\
           at emitOne (events.js:116:13)\n\
           at TLSSocket.emit (events.js:211:7)\n\
           at emitErrorNT (internal/streams/destroy.js:64:8)\n\
           at _combinedTickCallback (internal/process/next_tick.js:138:11)\n\
           at process._tickCallback (internal/process/next_tick.js:180:9)\n\
           ',
       message: 'Error: connect ECONNREFUSED 0.0.0.0:443',
       cause:
        { Error: connect ECONNREFUSED 0.0.0.0:443
    at Object._errnoException (util.js:1024:11)
    at _exceptionWithHostPort (util.js:1046:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1182:14)

          code: 'ECONNREFUSED',
          errno: 'ECONNREFUSED',
          syscall: 'connect',
          address: '0.0.0.0',
          port: 443 },
       error:
        { Error: connect ECONNREFUSED 0.0.0.0:443
    at Object._errnoException (util.js:1024:11)
    at _exceptionWithHostPort (util.js:1046:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1182:14)

          code: 'ECONNREFUSED',
          errno: 'ECONNREFUSED',
          syscall: 'connect',
          address: '0.0.0.0',
          port: 443 },
       options:
        { timeout: 90000,
          agent:
           CombinedAgent {
             familyCache: { 'localhost': 4 },
             httpAgent:
              HttpAgent {
                domain: null,
                _events: { free: [Function] },
                _eventsCount: 1,
                _maxListeners: undefined,
                defaultPort: 80,
                protocol: 'http:',
                options: { keepAlive: true, path: null },
                requests: {},
                sockets: {},
                freeSockets: {},
                keepAliveMsecs: 1000,
                keepAlive: true,
                maxSockets: Infinity,
                maxFreeSockets: 256,
                httpsAgent:
                 Agent {
                   domain: null,
                   _events: { free: [Function] },
                   _eventsCount: 1,
                   _maxListeners: undefined,
                   defaultPort: 443,
                   protocol: 'https:',
                   options: { keepAlive: true, path: null },
                   requests: {},
                   sockets: {},
                   freeSockets: {},
                   keepAliveMsecs: 1000,
                   keepAlive: true,
                   maxSockets: Infinity,
                   maxFreeSockets: 256,
                   maxCachedSessions: 100,
                   _sessionCache: { map: {}, list: [] } } },
             httpsAgent:
              HttpsAgent {
                domain: null,
                _events: { free: [Function] },
                _eventsCount: 1,
                _maxListeners: undefined,
                defaultPort: 443,
                protocol: 'https:',
                options: { keepAlive: true, path: null },
                requests: {},
                sockets: {},
                freeSockets:
                 { 'localhost:443::4::::::false::':
                    [ TLSSocket {
                        _tlsOptions:
                         { pipe: false,
                           secureContext: SecureContext { context: SecureContext {} },
                           isServer: false,
                           requestCert: true,
                           rejectUnauthorized: false,
                           session: undefined,
                           NPNProtocols: undefined,
                           ALPNProtocols: undefined,
                           requestOCSP: undefined },
                        _secureEstablished: true,
                        _securePending: false,
                        _newSessionPending: false,
                        _controlReleased: true,
                        _SNICallback: null,
                        servername: null,
                        npnProtocol: false,
                        alpnProtocol: false,
                        authorized: true,
                        authorizationError: null,
                        encrypted: true,
                        _events:
                         { close:
                            [ [Function],
                              { [Function: bound onceWrapper] listener: [Function] },
                              [Function: onClose] ],
                           end: { [Function: bound onceWrapper] listener: [Function: onend] },
                           finish: [Function: onSocketFinish],
                           _socketEnd: [Function: onSocketEnd],
                           secure: [Function],
                           free: [Function: onFree],
                           agentRemove: [Function: onRemove],
                           drain: [Function: ondrain],
                           error: { [Function: bound onceWrapper] listener: [Function: freeSocketErrorListener] } },
                        _eventsCount: 9,
                        connecting: false,
                        _hadError: false,
                        _handle:
                         TLSWrap {
                           _parent:
                            TCP {
                              reading: [Getter/Setter],
                              owner: [Circular],
                              onread: null,
                              onconnection: null,
                              writeQueueSize: 0 },
                           _parentWrap: undefined,
                           _secureContext: SecureContext { context: SecureContext {} },
                           reading: true,
                           owner: [Circular],
                           onread: [Function: onread],
                           writeQueueSize: 0,
                           onhandshakestart: [Function],
                           onhandshakedone: [Function],
                           onocspresponse: [Function],
                           onerror: [Function] },
                        _parent: null,
                        _host: 'localhost',
                        _readableState:
                         ReadableState {
                           objectMode: false,
                           highWaterMark: 16384,
                           buffer: BufferList { head: null, tail: null, length: 0 },
                           length: 0,
                           pipes: null,
                           pipesCount: 0,
                           flowing: true,
                           ended: false,
                           endEmitted: false,
                           reading: true,
                           sync: false,
                           needReadable: true,
                           emittedReadable: false,
                           readableListening: false,
                           resumeScheduled: false,
                           destroyed: false,
                           defaultEncoding: 'utf8',
                           awaitDrain: 0,
                           readingMore: false,
                           decoder: null,
                           encoding: null },
                        readable: true,
                        domain: null,
                        _maxListeners: undefined,
                        _writableState:
                         WritableState {
                           objectMode: false,
                           highWaterMark: 16384,
                           finalCalled: false,
                           needDrain: false,
                           ending: false,
                           ended: false,
                           finished: false,
                           destroyed: false,
                           decodeStrings: false,
                           defaultEncoding: 'utf8',
                           length: 0,
                           writing: false,
                           corked: 0,
                           sync: false,
                           bufferProcessing: false,
                           onwrite: [Function: bound onwrite],
                           writecb: null,
                           writelen: 0,
                           bufferedRequest: null,
                           lastBufferedRequest: null,
                           pendingcb: 0,
                           prefinished: false,
                           errorEmitted: false,
                           bufferedRequestCount: 0,
                           corkedRequestsFree:
                            { next: null,
                              entry: null,
                              finish: [Function: bound onCorkedFinish] } },
                        writable: true,
                        allowHalfOpen: false,
                        _bytesDispatched: 348,
                        _sockname: null,
                        _pendingData: null,
                        _pendingEncoding: '',
                        server: undefined,
                        _server: null,
                        ssl:
                         TLSWrap {
                           _parent:
                            TCP {
                              reading: [Getter/Setter],
                              owner: [Circular],
                              onread: null,
                              onconnection: null,
                              writeQueueSize: 0 },
                           _parentWrap: undefined,
                           _secureContext: SecureContext { context: SecureContext {} },
                           reading: true,
                           owner: [Circular],
                           onread: [Function: onread],
                           writeQueueSize: 0,
                           onhandshakestart: [Function],
                           onhandshakedone: [Function],
                           onocspresponse: [Function],
                           onerror: [Function] },
                        _requestCert: true,
                        _rejectUnauthorized: false,
                        parser: null,
                        _httpMessage: null,
                        read: [Function],
                        _consuming: true,
                        _idleTimeout: -1,
                        _idleNext: null,
                        _idlePrev: null,
                        _idleStart: 41856,
                        _destroyed: false,
                        [Symbol(asyncId)]: -1,
                        [Symbol(bytesRead)]: 0,
                        [Symbol(asyncId)]: 3173,
                        [Symbol(triggerAsyncId)]: 3163 } ] },
                keepAliveMsecs: 1000,
                keepAlive: true,
                maxSockets: Infinity,
                maxFreeSockets: 256,
                maxCachedSessions: 100,
                _sessionCache:
                 { map:
                    { 'localhost:443::4::::::false::': <Buffer 30 82 08 3c 02 01 01 02 02 03 03 04 02 c0 2f 04 20 e7 f6 ff ce 61 67 f3 90 b7 4f 56 d1 a5 0f 5f 09 65 50 61 20 74 54 db d8 bb c9 59 f6 d7 c4 e4 46 04 ... > },
                   list:
                    [ 'localhost:443::4::::::false::' ] } } },
          headers:
           { Connection: 'keep-alive',
             'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Cypress/3.3.1 Chrome/61.0.3163.100 Electron/2.0.18 Safari/537.36',
             accept: '*/*' },
          proxy: null,
          url: 'https://localhost/',
          method: 'GET',
          gzip: true,
          followRedirect: [Function],
          failOnStatusCode: false,
          retryOnNetworkFailure: true,
          retryOnStatusCodeFailure: false,
          jar:
           { _jar: CookieJar { enableLooseMode: true, store: { idx: {} } },
             toJSON: [Function: toJSON],
             setCookie: [Function: setCookie],
             getCookieString: [Function: getCookieString],
             getCookies: [Function: getCookies] },
          cookies: true,
          strictSSL: false,
          simple: false,
          resolveWithFullResponse: true,
          followAllRedirects: true,
          requestId: 'request3',
          retryIntervals: [ 0, 1000, 2000, 2000 ],
          delaysRemaining: [],
          callback: [Function: RP$callback],
          transform: undefined,
          transform2xxOnly: false },
       response: undefined
    }

The important part is that this object contains circular references:

    owner: [Circular],

On request error, this object is sent to socket.io’s callback function https://github.com/cypress-io/cypress/blob/develop/packages/server/lib/socket.coffee#L315-L319

This is a problem because Socket.io scans arguments for binary data that doesn’t deal with circular reference. https://github.com/socketio/socket.io/blob/master/lib/socket.js#L374-L391 https://github.com/expanse-org/socketio-app/blob/master/node_modules/has-binary2/index.js

There is already some filtering done to errors captured and raised back to the execution flow. https://github.com/cypress-io/cypress/blob/develop/packages/server/lib/errors.coffee#L808-L828

An additional operation to would be to make sure that it doesn’t contain circular reference. I’d suggest using a library like fclone for this. https://github.com/soyuka/fclone

Versions

  • Cypress 3.3.1
  • Electron 61 (headless)
  • CentOS 7

Note: OSX with electron or chrome did not reproduce the issue.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:6
  • Comments:23 (8 by maintainers)

github_iconTop GitHub Comments

13reactions
garethleonardcommented, Jun 19, 2019

Do you have an ETA for release on #4469?

2reactions
cypress-bot[bot]commented, Jun 27, 2019

Released in 3.3.2.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Jest crashes with error: Maximum call stack size exceeded on ...
In the Run window I get the error "RangeError: Maximum call stack size exceeded" with the call stack. WebStorm sets the project root...
Read more >
JavaScript RangeError: Maximum Call Stack Size Exceeded
The RangeError: Maximum call stack size exceeded is thrown when a function call is made that exceeds the call stack size. This can...
Read more >
`Maximum call stack size exceeded` error when clicking ...
When clicking the "Show unchanged lines" in an MR diff for a large file, the browser hangs. In Chrome, I get a Maximum...
Read more >
Node.js - Maximum call stack size exceeded
js throws a "RangeError: Maximum call stack size exceeded" exception caused by too many recursive calls. I tried to increase Node.js stack size ......
Read more >
cypress-io/cypress - Gitter
I am getting "Uncaught RangeError: Maximum call stack size exceeded. ... (of ish 40) that crashes my computer if I rerun it a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found