{"record":{"id":"f23bcbcb80c0234d","repo":"astral-sh/ruff","slug":"tried-to-get-qos-of-thread-which-has-opted-out-of","errorCode":null,"errorMessage":"tried to get QoS of thread which has opted out of QoS","messagePattern":"tried to get QoS of thread which has opted out of QoS","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/ty_server/src/server/schedule/thread/priority.rs","lineNumber":267,"sourceCode":"            let errno = unsafe { *libc::__error() };\n            unreachable!(\"`pthread_get_qos_class_np` failed unexpectedly (os error {errno})\");\n        }\n\n        match qos_class_raw {\n            libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE => Some(QoSClass::UserInteractive),\n            libc::qos_class_t::QOS_CLASS_USER_INITIATED => Some(QoSClass::UserInitiated),\n            libc::qos_class_t::QOS_CLASS_DEFAULT => None, // QoS has never been set\n            libc::qos_class_t::QOS_CLASS_UTILITY => Some(QoSClass::Utility),\n            libc::qos_class_t::QOS_CLASS_BACKGROUND => Some(QoSClass::Background),\n\n            libc::qos_class_t::QOS_CLASS_UNSPECIFIED => {\n                // Using manual scheduling APIs causes threads to “opt out” of QoS.\n                // At this point they become incompatible with QoS,\n                // and as such have the “unspecified” QoS class.\n                //\n                // Panic instead of returning an error\n                // to maintain the invariant that we only use QoS APIs.\n                panic!(\"tried to get QoS of thread which has opted out of QoS\")\n            }\n        }\n    }\n\n    pub(super) fn thread_priority_to_qos_class(priority: ThreadPriority) -> QoSClass {\n        match priority {\n            ThreadPriority::Worker => QoSClass::Utility,\n            ThreadPriority::LatencySensitive => QoSClass::UserInitiated,\n        }\n    }\n}\n\n// FIXME: Windows has QoS APIs, we should use them!\n#[cfg(not(target_vendor = \"apple\"))]\nmod imp {\n    use super::ThreadPriority;\n\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ty_server/src/server/schedule/thread/priority.rs#L249-L285","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Panic occurs inside ty; isolate it at the thread boundary:\nstd::panic::catch_unwind(|| ty_scheduler::current_priority())\n    .map_err(|_| \"QoS unavailable: run on a thread that has not opted out\")","preventionTips":["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."],"tags":["macos","qos","threads","panic","lsp"],"backgroundTag":"thread-qos-opt-out","analyzedSha":"26f38c119cac42e4d320ba08f09224fdec74af2c","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}