Skip to content

[Bug]: Network request in utility process fails after event loop is blocked for a few seconds (regression in v29) #43186

@nikwen

Description

@nikwen

Preflight Checklist

Electron Version

31.3.1

What operating system(s) are you using?

macOS

Operating System Version

macOS Sonoma 14.6

What arch are you using?

arm64 (including Apple Silicon)

Last Known Working Electron version

28.3.3

Expected Behavior

Network requests work when performed after long-running tasks in a utility process.

Actual Behavior

If code in a utility process blocks the event loop for a few seconds and then performs a network request, that network request fails with ECONNRESET. If we wait for 10ms before running the network request, it works.

This is bad because utility processes are made for these long-running tasks that can block the event loop. We don't want that code in our main processes.

This is a regression in Electron v29 and above (via #40017?). The code runs fine on Electron v28.

Testcase Gist URL

https://gist.github.com/nikwen/6a66d9fa7a469a266490e88fa0c8222a

Additional Information

Full command line output & error message

From the previous reproduction code (because Fiddle cuts off the error message).

Show
Server up
Request received
First request worked
AxiosError: read ECONNRESET
    at AxiosError.from (/Users/nikwen/Projects/Web/electron-utility-process-bug/node_modules/axios/dist/node/axios.cjs:873:14)
    at RedirectableRequest.handleRequestError (/Users/nikwen/Projects/Web/electron-utility-process-bug/node_modules/axios/dist/node/axios.cjs:3152:25)
    at RedirectableRequest.emit (node:events:519:28)
    at eventHandlers.<computed> (/Users/nikwen/Projects/Web/electron-utility-process-bug/node_modules/follow-redirects/index.js:38:24)
    at ClientRequest.emit (node:events:519:28)
    at Socket.socketErrorListener (node:_http_client:500:9)
    at Socket.emit (node:events:519:28)
    at emitErrorNT (node:internal/streams/destroy:169:8)
    at emitErrorCloseNT (node:internal/streams/destroy:128:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
    at Axios.request (/Users/nikwen/Projects/Web/electron-utility-process-bug/node_modules/axios/dist/node/axios.cjs:4262:41)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async makeRequest (/Users/nikwen/Projects/Web/electron-utility-process-bug/src/utility.js:38:5) {
  syscall: 'read',
  code: 'ECONNRESET',
  errno: -54,
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [ 'xhr', 'http', 'fetch' ],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function], Blob: [class Blob] },
    validateStatus: [Function: validateStatus],
    headers: Object [AxiosHeaders] {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/x-www-form-urlencoded',
      'User-Agent': 'axios/1.7.3',
      'Accept-Encoding': 'gzip, compress, deflate, br'
    },
    method: 'post',
    url: 'http://127.0.0.1:3000',
    data: undefined
  },
  request: <ref *1> Writable {
    _events: {
      close: undefined,
      error: [Function: handleRequestError],
      prefinish: undefined,
      finish: undefined,
      drain: undefined,
      response: [Function: handleResponse],
      socket: [Function: handleRequestSocket]
    },
    _writableState: WritableState {
      highWaterMark: 16384,
      length: 0,
      corked: 0,
      onwrite: [Function: bound onwrite],
      writelen: 0,
      bufferedIndex: 0,
      pendingcb: 0,
      [Symbol(kState)]: 17580812,
      [Symbol(kBufferedValue)]: null
    },
    _maxListeners: undefined,
    _options: {
      maxRedirects: 21,
      maxBodyLength: Infinity,
      protocol: 'http:',
      path: '/',
      method: 'POST',
      headers: [Object: null prototype],
      agents: [Object],
      auth: undefined,
      family: undefined,
      beforeRedirect: [Function: dispatchBeforeRedirect],
      beforeRedirects: [Object],
      hostname: '127.0.0.1',
      port: '3000',
      agent: undefined,
      nativeProtocols: [Object],
      pathname: '/'
    },
    _ended: true,
    _ending: true,
    _redirectCount: 0,
    _redirects: [],
    _requestBodyLength: 0,
    _requestBodyBuffers: [],
    _eventsCount: 3,
    _onNativeResponse: [Function (anonymous)],
    _currentRequest: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: false,
      chunkedEncoding: false,
      shouldKeepAlive: true,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      strictContentLength: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: [Socket],
      _header: 'POST / HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Content-Type: application/x-www-form-urlencoded\r\n' +
        'User-Agent: axios/1.7.3\r\n' +
        'Accept-Encoding: gzip, compress, deflate, br\r\n' +
        'Host: 127.0.0.1:3000\r\n' +
        'Connection: keep-alive\r\n' +
        'Content-Length: 0\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      joinDuplicateHeaders: undefined,
      path: '/',
      _ended: false,
      res: null,
      aborted: false,
      timeoutCb: [Function: emitRequestTimeout],
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: true,
      host: '127.0.0.1',
      protocol: 'http:',
      _redirectable: [Circular *1],
      [Symbol(shapeMode)]: false,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(errored)]: null,
      [Symbol(kHighWaterMark)]: 16384,
      [Symbol(kRejectNonStandardBodyWrites)]: false,
      [Symbol(kUniqueHeaders)]: null
    },
    _currentUrl: 'http://127.0.0.1:3000/',
    [Symbol(shapeMode)]: true,
    [Symbol(kCapture)]: false
  },
  cause: Error: read ECONNRESET
      at TCP.onStreamRead (node:internal/stream_base_commons:218:20) {
    errno: -54,
    code: 'ECONNRESET',
    syscall: 'read'
  }
}

Affected platforms

  • macOS 14.6
  • Windows 10
  • (Linux not tested.)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions