Environment
- codex-cli 0.118.0
- macOS 26.4 (25E246), Apple M4 Pro
- Python 3.14.2, MLX 0.31.0
- Config:
sandbox = "danger-full-access", bypass-sandbox = true, CLI alias with --dangerously-bypass-approvals-and-sandbox
Description
When Codex spawns a Python subprocess that imports mlx.core (e.g., for local voice transcription via mlx-whisper), the process crashes with SIGABRT due to an uncaught NSRangeException:
*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty array
The crash occurs in mlx::core::metal::Device::Device() during Metal GPU device enumeration. Metal's MTLCopyAllDevices() returns an empty array because the Seatbelt sandbox profile restricts IOKit access.
Root Cause
The Seatbelt profile compiled into the Codex binary only allows:
(allow iokit-open
(iokit-registry-entry-class "RootDomainUserClient"))
This applies even in danger-full-access mode. Metal GPU enumeration requires IOKit access to GPU driver classes (e.g., AGXMetalG16X on Apple Silicon), which is not permitted.
Reproduction
Minimal reproduction without Codex, confirming the Seatbelt IOKit restriction is the root cause:
# This crashes with the identical NSRangeException:
sandbox-exec -p '(version 1)(allow default)(deny iokit-open)' \
python3 -c "import mlx.core"
# This works fine (full IOKit access):
sandbox-exec -p '(version 1)(allow default)' \
python3 -c "import mlx.core; print(mlx.core.default_device())"
Expected Behavior
danger-full-access mode (and --dangerously-bypass-approvals-and-sandbox) should grant unrestricted IOKit access, allowing Metal/GPU operations in child processes.
Suggested Fix
Add an unrestricted IOKit rule to the danger-full-access sandbox template:
Or, if a scoped approach is preferred:
(allow iokit-open
(iokit-registry-entry-class "RootDomainUserClient")
(iokit-registry-entry-class "AGXDeviceUserClient")
(iokit-registry-entry-class "IOGPUDeviceUserClient"))
Crash Report (abbreviated)
Process: Python
Parent: codex
Exception: EXC_CRASH (SIGABRT)
Reason: *** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty array
Crash thread backtrace:
CoreFoundation -[__NSArray0 objectAtIndex:]
libmlx.dylib mlx::core::metal::Device::Device()
libmlx.dylib mlx::core::metal::device(mlx::core::Device)
libmlx.dylib mlx::core::metal::MetalAllocator::MetalAllocator()
libmlx.dylib mlx::core::allocator::allocator()
libmlx.dylib mlx::core::random::key(unsigned long long)
core.cpython-314-darwin.so [module init]
Environment
sandbox = "danger-full-access",bypass-sandbox = true, CLI alias with--dangerously-bypass-approvals-and-sandboxDescription
When Codex spawns a Python subprocess that imports
mlx.core(e.g., for local voice transcription via mlx-whisper), the process crashes withSIGABRTdue to an uncaughtNSRangeException:The crash occurs in
mlx::core::metal::Device::Device()during Metal GPU device enumeration. Metal'sMTLCopyAllDevices()returns an empty array because the Seatbelt sandbox profile restricts IOKit access.Root Cause
The Seatbelt profile compiled into the Codex binary only allows:
(allow iokit-open (iokit-registry-entry-class "RootDomainUserClient"))This applies even in
danger-full-accessmode. Metal GPU enumeration requires IOKit access to GPU driver classes (e.g.,AGXMetalG16Xon Apple Silicon), which is not permitted.Reproduction
Minimal reproduction without Codex, confirming the Seatbelt IOKit restriction is the root cause:
Expected Behavior
danger-full-accessmode (and--dangerously-bypass-approvals-and-sandbox) should grant unrestricted IOKit access, allowing Metal/GPU operations in child processes.Suggested Fix
Add an unrestricted IOKit rule to the
danger-full-accesssandbox template:Or, if a scoped approach is preferred:
Crash Report (abbreviated)