astral-sh/ruff · critical

tried to set QoS of thread which has opted out of QoS (os er

Error message

tried to set QoS of thread which has opted out of QoS (os error {errno})

What it means

On macOS, ty's scheduler sets the current thread's QoS class via `pthread_set_qos_class_self_np`. If the thread has opted out of the QoS system (e.g. a prior call to `pthread_setschedparam`), the call fails with EPERM, and ty panics because its design invariant is that it only ever uses QoS-compatible scheduling APIs. This is a macOS-only, internal-invariant panic.

Source

Thrown at crates/ty_server/src/server/schedule/thread/priority.rs:204

        #[expect(unsafe_code)]
        let code = unsafe { libc::pthread_set_qos_class_self_np(c, 0) };

        if code == 0 {
            return;
        }

        #[expect(unsafe_code)]
        let errno = unsafe { *libc::__error() };

        match errno {
            libc::EPERM => {
                // This thread has been excluded from the QoS system
                // due to a previous call to a function such as `pthread_setschedparam`
                // which is incompatible with QoS.
                //
                // Panic instead of returning an error
                // to maintain the invariant that we only use QoS APIs.
                panic!("tried to set QoS of thread which has opted out of QoS (os error {errno})")
            }

            libc::EINVAL => {
                // This is returned if we pass something other than a qos_class_t
                // to `pthread_set_qos_class_self_np`.
                //
                // This is impossible, so again panic.
                unreachable!(
                    "invalid qos_class_t value was passed to pthread_set_qos_class_self_np"
                )
            }

            _ => {
                // `pthread_set_qos_class_self_np`’s documentation
                // does not mention any other errors.
                unreachable!("`pthread_set_qos_class_self_np` returned unexpected error {errno}")
            }
        }

View on GitHub (pinned to 26f38c119c)

Solutions

  1. Run the ty server on threads that have not had their scheduling configured via pthread_setschedparam or similar APIs.
  2. Remove or defer manual thread-priority calls in the embedding code before starting ty's scheduler.
  3. Use fresh default-priority threads for the server's worker pool.

Example fix

// before: host code sets a fixed priority before starting ty
pthread_setschedparam(thread, SCHED_FIFO, &param);
ty_server::start(...);
// after: start ty on an untouched thread, then customize elsewhere
ty_server::start(...);
Defensive patterns

Strategy: try-catch

Validate before calling

// macOS: ensure the host thread has not opted out of QoS before hosting ty
let is_qos_compatible = std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("macos")
    || !manual_scheduling_used;
if !is_qos_compatible { /* run ty on a fresh default-priority thread */ }

Try / catch

// The API panics, so guard by construction; catch at the thread boundary:
std::panic::catch_unwind(|| ty_server::run_on_current_thread())
    .map_err(|_| "thread opted out of QoS; re-run on a clean thread")

Prevention

When it happens

Trigger: Running ty's LSP server on macOS inside a thread that previously called `pthread_setschedparam` or another manual scheduling API, so `set_current_thread_qos_class` receives errno EPERM.

Common situations: Embedding ty's server into another application that manages its own thread priorities; running within runtimes or wrappers that adjust thread scheduling; macOS-only regressions when hosting the server in foreign threads.

Related errors


AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05). Data as JSON: /api/errors/90904f06b816b3d6. Report an issue: GitHub.