{"record":{"id":"5d1d6f13fcb6f566","repo":"expo/expo","slug":"process-exit-code-called-in-hermes-runtime","errorCode":null,"errorMessage":"process.exit(${code}) called in Hermes runtime","messagePattern":"process\\.exit\\((.+?)\\) called in Hermes runtime","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/expo-go/tools/device-transformer/globals.js","lineNumber":294,"sourceCode":"    const proc = {\n      env: {},\n      argv: ['jsc', 'device-transformer'],\n      execArgv: [],\n      platform: 'darwin',\n      arch: 'arm64',\n      version: 'v22.14.0',\n      versions: { node: '22.14.0', v8: '12.4' },\n      pid: 1,\n      title: 'jsc',\n      browser: false,\n      exitCode: 0,\n      cwd: () => '/project',\n      chdir: () => {\n        throw new Error('process.chdir not supported');\n      },\n      nextTick: (fn, ...args) => g.queueMicrotask(() => fn(...args)),\n      exit: (code) => {\n        throw new Error('process.exit(' + code + ') called in Hermes runtime');\n      },\n      hrtime: Object.assign(\n        (prev) => {\n          const ms = Date.now();\n          const s = Math.floor(ms / 1000),\n            ns = (ms % 1000) * 1e6;\n          if (prev) {\n            let ds = s - prev[0],\n              dns = ns - prev[1];\n            if (dns < 0) {\n              ds--;\n              dns += 1e9;\n            }\n            return [ds, dns];\n          }\n          return [s, ns];\n        },\n        { bigint: () => BigInt(Date.now()) * 1000000n }","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/expo/expo/blob/b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee/apps/expo-go/tools/device-transformer/globals.js#L276-L312","documentation":"Thrown by the process polyfill's exit() method in globals.js. Since the device-transformer runs inside the Expo Go app's Hermes/JSC runtime (not a Node process), calling process.exit would crash the app. The polyfill deliberately throws to make any accidental exit call loud and diagnosable rather than silently killing the runtime.","triggerScenarios":"Any bundled module calls process.exit(code) during the on-device transform. The polyfill constructs an error with the exit code in the message.","commonSituations":"A babel plugin, metro utility, or dependency calls process.exit on an error path (e.g., version mismatch, missing config); a dependency's CLI bootstrap code calls exit during module initialization.","solutions":["Trace the stack to find which module calls process.exit and what condition triggers it — the error path likely indicates a real problem (missing config, version mismatch).","Fix the underlying condition that causes the exit call.","If the exit is on a dead code path, stub the module via an esbuild onLoad handler."],"exampleFix":"// before — throws, potentially masking the real issue\nexit: (code) => {\n  throw new Error('process.exit(' + code + ') called in Hermes runtime');\n},\n\n// after — log the stack before throwing for easier diagnosis\nexit: (code) => {\n  console.error('process.exit(' + code + ') called from:', new Error().stack);\n  throw new Error('process.exit(' + code + ') called in Hermes runtime');\n},","handlingStrategy":"try-catch","validationCode":"// Scan bundled source for process.exit usage\nfunction scanForProcessExit(sourceFiles) {\n  const offenders = [];\n  for (const { path, content } of sourceFiles) {\n    if (/process\\.exit\\s*\\(/.test(content)) {\n      offenders.push(path);\n    }\n  }\n  return offenders;\n}","typeGuard":null,"tryCatchPattern":"// Wrap transform calls to catch process.exit throws\ntry {\n  transformModule(source, filename, moduleId, depIds);\n} catch (err) {\n  if (err.message.includes('process.exit(')) {\n    // The real error is whatever caused the exit call — log full stack\n    console.error('Underlying error caused process.exit:', err.stack);\n  }\n  throw err;\n}","preventionTips":["Investigate any process.exit call in bundled code — it usually masks a real error condition.","Patch modules that call process.exit on dead code paths via esbuild onLoad handlers.","Fix the underlying condition (missing config, version mismatch) that triggers the exit."],"tags":["hermes","runtime","process","device-transformer","globals","expo-go"],"backgroundTag":null,"analyzedSha":"b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee","analyzedAt":"2026-08-12T15:59:58.304Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}