Summary
getTorchBuildInfo probes for torch by running python -c "try: import torch ... except Exception: ...". On macOS, when the probed interpreter has torch and numpy installed such that two OpenMP runtimes get loaded, import torch does not raise — it calls abort() inside libomp. A Python except Exception cannot catch SIGABRT, so the guard is bypassed, the interpreter dies, and macOS writes a crash report. Because the probe runs on a schedule, this produces a steady stream of crash reports for as long as the controller is running.
Environment
- Controller:
main @ 52c2b20 (v2.9.10)
- Desktop app: 2.9.10
- macOS 27.0 (26A5388g), Apple M5 Pro (arm64)
- Probed interpreter: Homebrew Python 3.14.6 with
torch and numpy installed
Affected code
controller/src/modules/system/platform/torch-info.ts:6-9
const TORCH_PROBE_ARGS = [
"-c",
"import json\ntry:\n import torch\n print(...)\nexcept Exception:\n print(...)",
];
What actually happens
import torch triggers validate_numpy_for_dlpack_deleter_bug(), which imports numpy, which initializes OpenBLAS. Two distinct libomp.dylib images end up mapped into the one process — one pulled in by libtorch/libc10, the other by libopenblasp via libgfortran — and the second registration aborts:
0 libsystem_kernel.dylib __pthread_kill + 8
2 libsystem_c.dylib abort + 148
3 libomp.dylib __kmp_abort_process + 52
4 libomp.dylib __kmp_fatal + 56
5 libomp.dylib __kmp_register_library_startup() + 1740
9 libomp.dylib omp_get_max_threads + 28
10 libopenblasp-r0.3.34.dylib blas_thread_init + 12
11 libopenblasp-r0.3.34.dylib gotoblas_init + 76
...
102 libtorch_python.dylib torch::utils::validate_numpy_for_dlpack_deleter_bug() + 56
103 libtorch_python.dylib THPVariable_initModule(_object*) + 1892
Exception Type: EXC_CRASH (SIGABRT)
Termination Reason: Namespace SIGNAL, Code 6, Abort trap: 6
Parent Process: bun
Coalition: org.local.studio.controller
Both libomp images in Binary Images, confirming the duplicate load:
0x10a5dc000 libomp.dylib <e56febf1-776c-35bb-b9a1-8c978a01425c> # via libtorch/libc10
0x10a768000 libomp.dylib <e08eca60-8306-3d5b-8a9c-5673087c6760> # via OpenBLAS/libgfortran
Reproduction
- Install torch and numpy into a macOS Python that ends up with two OpenMP runtimes (Homebrew
python@3.14 with Homebrew-built torch reproduces it reliably).
- Install and start the controller so that interpreter is the one probed.
- Watch
~/Library/Logs/DiagnosticReports/Python-*.ips.
Observed: 10 crash reports in roughly five minutes, one about every 31 seconds, each with the stack above.
Impact
Functionally this degrades correctly — parseTorchBuildOutput returns EMPTY_TORCH on non-zero status, so torch info is simply reported as unavailable. The problem is the side effects:
- A macOS crash report per probe, indefinitely. This reads to a user as "the app is crash-looping", which is how I found it.
- On systems with crash reporting UI enabled, repeated user-visible crash notifications.
- Torch is never detected on these systems, even though it is installed.
Suggested fix
Set KMP_DUPLICATE_LIB_OK=TRUE in the probe's child environment. It is contained to this one short-lived probe, so the usual caveats about that flag don't apply to any real compute.
runCommandAsyncEffect(python, TORCH_PROBE_ARGS, {
timeoutMs: TORCH_PROBE_TIMEOUT_MS,
environment: { ...process.env, KMP_DUPLICATE_LIB_OK: "TRUE" },
})
OMP_NUM_THREADS=1 alongside it would also keep the probe from spinning up a thread pool it never uses.
Verified locally: adding KMP_DUPLICATE_LIB_OK=TRUE to the controller's launchd EnvironmentVariables stopped the crashes outright — zero new reports in 100s, against one per ~31s before.
It may also be worth treating a signal-terminated probe distinctly from a clean non-zero exit, so a crashing child is logged as a probe failure rather than silently folded into "torch not installed".
Summary
getTorchBuildInfoprobes for torch by runningpython -c "try: import torch ... except Exception: ...". On macOS, when the probed interpreter has torch and numpy installed such that two OpenMP runtimes get loaded,import torchdoes not raise — it callsabort()inside libomp. A Pythonexcept Exceptioncannot catchSIGABRT, so the guard is bypassed, the interpreter dies, and macOS writes a crash report. Because the probe runs on a schedule, this produces a steady stream of crash reports for as long as the controller is running.Environment
main@52c2b20(v2.9.10)torchandnumpyinstalledAffected code
controller/src/modules/system/platform/torch-info.ts:6-9What actually happens
import torchtriggersvalidate_numpy_for_dlpack_deleter_bug(), which imports numpy, which initializes OpenBLAS. Two distinctlibomp.dylibimages end up mapped into the one process — one pulled in bylibtorch/libc10, the other bylibopenblaspvialibgfortran— and the second registration aborts:Both libomp images in
Binary Images, confirming the duplicate load:Reproduction
python@3.14with Homebrew-built torch reproduces it reliably).~/Library/Logs/DiagnosticReports/Python-*.ips.Observed: 10 crash reports in roughly five minutes, one about every 31 seconds, each with the stack above.
Impact
Functionally this degrades correctly —
parseTorchBuildOutputreturnsEMPTY_TORCHon non-zero status, so torch info is simply reported as unavailable. The problem is the side effects:Suggested fix
Set
KMP_DUPLICATE_LIB_OK=TRUEin the probe's child environment. It is contained to this one short-lived probe, so the usual caveats about that flag don't apply to any real compute.OMP_NUM_THREADS=1alongside it would also keep the probe from spinning up a thread pool it never uses.Verified locally: adding
KMP_DUPLICATE_LIB_OK=TRUEto the controller's launchdEnvironmentVariablesstopped the crashes outright — zero new reports in 100s, against one per ~31s before.It may also be worth treating a signal-terminated probe distinctly from a clean non-zero exit, so a crashing child is logged as a probe failure rather than silently folded into "torch not installed".