astral-sh/ruff · critical
tried to get QoS of thread which has opted out of QoS
Error message
tried to get QoS of thread which has opted out of QoS
What it means
This is the read-side counterpart of the QoS invariant panic: `get_current_thread_qos_class` calls a macOS API to query the thread's QoS class and receives the 'unspecified' class, which means the thread has opted out of QoS (usually via manual scheduling APIs). Because ty assumes it exclusively uses QoS-compatible APIs, this state is treated as a broken invariant and panics.
Source
Thrown at crates/ty_server/src/server/schedule/thread/priority.rs:267
let errno = unsafe { *libc::__error() };
unreachable!("`pthread_get_qos_class_np` failed unexpectedly (os error {errno})");
}
match qos_class_raw {
libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE => Some(QoSClass::UserInteractive),
libc::qos_class_t::QOS_CLASS_USER_INITIATED => Some(QoSClass::UserInitiated),
libc::qos_class_t::QOS_CLASS_DEFAULT => None, // QoS has never been set
libc::qos_class_t::QOS_CLASS_UTILITY => Some(QoSClass::Utility),
libc::qos_class_t::QOS_CLASS_BACKGROUND => Some(QoSClass::Background),
libc::qos_class_t::QOS_CLASS_UNSPECIFIED => {
// Using manual scheduling APIs causes threads to “opt out” of QoS.
// At this point they become incompatible with QoS,
// and as such have the “unspecified” QoS class.
//
// Panic instead of returning an error
// to maintain the invariant that we only use QoS APIs.
panic!("tried to get QoS of thread which has opted out of QoS")
}
}
}
pub(super) fn thread_priority_to_qos_class(priority: ThreadPriority) -> QoSClass {
match priority {
ThreadPriority::Worker => QoSClass::Utility,
ThreadPriority::LatencySensitive => QoSClass::UserInitiated,
}
}
}
// FIXME: Windows has QoS APIs, we should use them!
#[cfg(not(target_vendor = "apple"))]
mod imp {
use super::ThreadPriority;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]View on GitHub (pinned to 26f38c119c)
Solutions
- Ensure the server's threads avoid `pthread_setschedparam` and other APIs that opt out of QoS.
- Run ty's scheduler on freshly created, default-scheduling threads.
- Reconfigure the embedding application to use QoS APIs (e.g. pthread_set_qos_class_self_np / dispatch QoS) instead of legacy priority APIs.
Defensive patterns
Strategy: try-catch
Try / catch
// Panic occurs inside ty; isolate it at the thread boundary:
std::panic::catch_unwind(|| ty_scheduler::current_priority())
.map_err(|_| "QoS unavailable: run on a thread that has not opted out") Prevention
- Avoid mixing manual scheduling APIs with QoS on the same thread.
- Run ty's scheduler on freshly created macOS threads.
- Prefer dispatch/NSThread QoS mechanisms in the embedding app.
When it happens
Trigger: Calling into ty's scheduler (priority handling on macOS) from a thread that previously used manual scheduling APIs, so the queried QoS class is QOS_CLASS_UNSPECIFIED.
Common situations: Embedding the ty LSP server in applications or plugins that set thread priorities with pthread APIs; running the server inside native thread pools with custom scheduling on macOS.
Related errors
- tried to set QoS of thread which has opted out of QoS (os er
- InternalError
- Server notebook document could not be converted to ty's note
- `python_extension` is not expected to be combined with the i
- InternalError
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/f23bcbcb80c0234d.
Report an issue: GitHub.