Skip to content

ParallelFileReader: uncatchable fatal error when pread lands at EOF #4526

Description

@pseudobacon

Summary

Loading .safetensors files through the parallel file reader can abort the process with an uncatchable fatal error when a pread lands at/after EOF. The std::runtime_error thrown by ParallelFileReader crosses the C API boundary and becomes a hard crash instead of a catchable error.

Reproduction

Any multi-reader safetensors load where a reader's pread returns 0 (read at/after EOF):

// mlx/io/load.cpp  (ParallelFileReader)
// load.cpp:345  static ThreadPool* thread_pool = new ThreadPool{4};  // shared singleton
// load.cpp:378  throw std::runtime_error("[read] Unable to read from file.");  // sync tail read
// load.cpp:392  throw std::runtime_error("[read] Unable to read from file.");  // batched future

When this exception is thrown from a worker thread and propagated across the C API, it is not caught and the process aborts (observed as a Swift fatal error on the consumer side).

Behavior

  • Non-deterministic: the crash fires only when a reader's pread returns 0 at the EOF boundary (a race with the shared ThreadPool{4} work distribution). Re-running the same load usually succeeds.
  • The crash is a process abort, not a catchable exception — no Swift/C caller can recover.

Affected versions

  • C++ MLX ce45c52 (v0.31.x) through 1f8e74e (v0.32.2) — the static ThreadPool* shared reader and the throw std::runtime_error on pread == 0 are present in both.

Smallest failing test

MixedPrecisionQuantLoadTests.perModuleOverridesApplied and MixedPrecisionQuantLoadTests.globalOnlyQuantizationFailsLoudly (and RerankerTests) trigger the multi-reader safetensors load and intermittently abort the test process at the C API boundary (mlx_c/transforms.cpp:73 / array.cpp:352).

Suggested fix

Catch/convert the std::runtime_error from ParallelFileReader before it crosses the C API (return an mlStatus/mlxError instead of throwing), and/or guard the EOF pread == 0 case so it does not throw on the tail read.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions