Skip to content

Throw meaningful error when Metal device is not found - #3428

Merged
angeloskath merged 1 commit into
ml-explore:mainfrom
dogukanveziroglu:fix-metal-headless-device-init
Apr 21, 2026
Merged

angeloskath merged 1 commit into
ml-explore:mainfrom
dogukanveziroglu:fix-metal-headless-device-init

Conversation

@dogukanveziroglu

@dogukanveziroglu dogukanveziroglu commented Apr 19, 2026 •

Copy link
Copy Markdown
Contributor

Proposed changes

In headless, sandboxed, or virtualized macOS sessions (PyInstaller
bundles, CI containers, automation runs) MTL::CopyAllDevices() returns
an empty NSArray. The current code immediately calls devices->object(0),
which raises an Objective-C NSRangeException that aborts the process
before the Python layer can catch it.

Guard the access with a count() > 0 check and surface a clear
std::runtime_error if both CopyAllDevices() and
CreateSystemDefaultDevice() fail. The fallback path is preserved.

This is the guard @awni proposed on the issue thread.

Refs #3148.

Verified locally: GPU build still loads and the full python/tests/
suite passes (662 passed, 9007 subtests, 0 regressions); patch source
review confirms guard + fallback + clear error message.

Checklist

Put an x in the boxes that apply.

  • I have read the CONTRIBUTING document
  • I have run pre-commit run --all-files to format my code / installed pre-commit prior to committing changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the necessary documentation (if needed)

In headless, sandboxed, or virtualized macOS sessions (PyInstaller
bundles, CI containers, automation runs) `MTL::CopyAllDevices()` returns
an empty NSArray. The current code immediately calls `devices->object(0)`,
which raises an Objective-C `NSRangeException` that aborts the process
before the Python layer can catch it.

Guard the access with a `count() > 0` check and surface a clear
`std::runtime_error` if both `CopyAllDevices()` and
`CreateSystemDefaultDevice()` fail. The fallback path is preserved.

Fixes ml-explore#3148.

@zcbenz zcbenz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very nice improvement, thanks!

It does not completely fix #3148 though: ideally no error should be thrown at all when there is no use of GPU device, i.e. following code should never throw:

import mlx.core as mx

print(mx.device_count(mx.gpu))

@dogukanveziroglu
dogukanveziroglu force-pushed the fix-metal-headless-device-init branch 2 times, most recently from c71e588 to b41c754 Compare April 20, 2026 12:17
@dogukanveziroglu

Copy link
Copy Markdown
Contributor Author

The simpler metal::is_available() change passed local tests, but on a deeper headless simulation I hit cascading failures in stream / encoder lookup paths that don't show up on a system with a GPU. Moving to draft so I can validate properly in a real headless vm.

@dogukanveziroglu
dogukanveziroglu marked this pull request as draft April 20, 2026 12:30
@zcbenz

zcbenz commented Apr 20, 2026

Copy link
Copy Markdown
Member

Properly handling headless env would require refactoring lots of different parts of code, I wouldn’t expect to finish it in a single PR. I think this PR’s original change that improved the error message was actually a very good start that we should merge first.

@dogukanveziroglu
dogukanveziroglu force-pushed the fix-metal-headless-device-init branch 3 times, most recently from 7361426 to 8ce25f0 Compare April 20, 2026 13:24
@dogukanveziroglu

Copy link
Copy Markdown
Contributor Author

Properly handling headless env would require refactoring lots of different parts of code, I wouldn’t expect to finish it in a single PR. I think this PR’s original change that improved the error message was actually a very good start that we should merge first.

Ok then I reverted it to initial commit.

@dogukanveziroglu
dogukanveziroglu marked this pull request as ready for review April 20, 2026 13:28

@zcbenz zcbenz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@zcbenz zcbenz changed the title Handle headless Metal device init gracefully Throw meaningful error when Metal device is not found Apr 20, 2026
@angeloskath
angeloskath merged commit 7d40a4f into ml-explore:main Apr 21, 2026
16 checks passed
@BrewTestBot BrewTestBot mentioned this pull request Apr 22, 2026
1 task done
@dogukanveziroglu
dogukanveziroglu deleted the fix-metal-headless-device-init branch April 22, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants