Troubleshooting#
This page describes common issues when using the MLX backend and how to debug them.
Debug Logging#
AOT (export/compilation) debugging#
Set ET_MLX_DEBUG=1 during export to see detailed debug logging from the partitioner and preprocessor — including ops-to-not-decompose lists, graph dumps, per-node support decisions, and serialization details:
ET_MLX_DEBUG=1 python my_export_script.py
Runtime per-op logging#
Per-op logging prints each MLX instruction as it executes, showing op names and tensor IDs. This is useful for correlating runtime behavior with the compiled graph.
When using pybindings (i.e. python install_executorch.py), per-op logging is compiled in by default. Just set the environment variable:
ET_MLX_ENABLE_OP_LOGGING=1 python my_inference_script.py
For C++ builds, you need to build with the debug preset first (which compiles in the logging code), then set the environment variable:
# Build with debug preset
cmake --workflow --preset mlx-debug
# Run with per-op logging enabled
ET_MLX_ENABLE_OP_LOGGING=1 ./cmake-out/my_app model.pte
The release preset (mlx-release) strips the logging code for performance.
Inspecting .pte Files#
The MLX backend includes a .pte inspector for debugging exported models. It can parse the ExecuTorch program structure, extract and decode the MLX delegate payload, and display instructions, tensor metadata, and I/O maps.
Basic usage#
Dump the full PTE structure as JSON:
python -m executorch.backends.mlx.pte_inspector model.pte
MLX summary#
Show a high-level summary of the MLX delegate (tensor counts, I/O maps, mutable buffers):
python -m executorch.backends.mlx.pte_inspector model.pte --mlx-summary
MLX instructions#
Show every instruction in the compiled graph with operands and parameters. This is useful for verifying quantization, inspecting fused patterns, and debugging incorrect outputs:
python -m executorch.backends.mlx.pte_inspector model.pte --mlx-instructions
Extract delegate payload#
Extract the raw MLX delegate payload to a binary file:
python -m executorch.backends.mlx.pte_inspector model.pte --extract-delegate mlx -o delegate.bin
Parse and dump the extracted payload as JSON:
python -m executorch.backends.mlx.pte_inspector model.pte --extract-delegate mlx --parse-mlx -o mlx_graph.json
All options#
Flag |
Description |
|---|---|
|
High-level summary (tensor counts, I/O maps) |
|
Detailed instruction list with operands |
|
Extract raw delegate payload by ID |
|
Parse extracted MLX payload to JSON (use with |
|
Index of delegate to extract (0-based, default: first match) |
|
Output format (default: json) |
|
Write output to file instead of stdout |
Common Issues#
Metal compiler not found#
Error: xcrun -sdk macosx --find metal fails.
Solution: Install the full Xcode application (not just Command Line Tools). The Metal compiler ships with Xcode. If Xcode is installed but not selected:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
MLXPartitioner must be used with to_edge_transform_and_lower()#
Error: RuntimeError when using the legacy to_edge() + to_backend() workflow.
Solution: Use to_edge_transform_and_lower() instead:
import torch
from executorch.backends.mlx import MLXPartitioner
from executorch.exir import to_edge_transform_and_lower
et_program = to_edge_transform_and_lower(
torch.export.export(model, example_inputs),
partitioner=[MLXPartitioner()],
).to_executorch()