zed-industries/zed · error

failed to spawn drop thread

Error message

failed to spawn drop thread

What it means

Panics in SyntaxSnapshot::drop's LazyLock initializer when std::sync::mpsc::channel creation succeeds but the dedicated drop thread (which offloads slow tree-sitter Tree deallocation) cannot be spawned. Spawn failure is close to impossible on desktop platforms (thread exhaustion / resource limits), but if it happens, every snapshot drop on that process panics because the sender can never be constructed.

Source

Thrown at crates/language/src/syntax_map.rs:56

pub struct SyntaxSnapshot {
    layers: SumTree<SyntaxLayerEntry>,
    parsed_version: clock::Global,
    interpolated_version: clock::Global,
    language_registry_version: usize,
    update_count: usize,
}

// Dropping deep treesitter Trees can be quite slow due to deallocating lots of memory.
// To avoid blocking the main thread, we offload the drop operation to a background thread.
impl Drop for SyntaxSnapshot {
    fn drop(&mut self) {
        static DROP_TX: LazyLock<std::sync::mpsc::Sender<SumTree<SyntaxLayerEntry>>> =
            LazyLock::new(|| {
                let (tx, rx) = std::sync::mpsc::channel();
                std::thread::Builder::new()
                    .name("SyntaxSnapshot::drop".into())
                    .spawn(move || while let Ok(_) = rx.recv() {})
                    .expect("failed to spawn drop thread");
                tx
            });
        // This does allocate a new Arc, but it's cheap and avoids blocking the main thread without needing to use an `Option` or `MaybeUninit`.
        let _ = DROP_TX.send(std::mem::replace(
            &mut self.layers,
            SumTree::from_summary(SyntaxLayerSummary {
                min_depth: Default::default(),
                max_depth: Default::default(),
                // Deliberately bogus anchors, doesn't matter in this context
                range: Anchor::min_min_range_for_buffer(BufferId::new(1).unwrap()),
                last_layer_range: Anchor::min_min_range_for_buffer(BufferId::new(1).unwrap()),
                last_layer_language: Default::default(),
                contains_unknown_injections: Default::default(),
            }),
        ));
    }
}

View on GitHub (pinned to 9d272b0363)

Solutions

  1. Check for thread/resource exhaustion (ulimit, RLIMIT_NPROC) on the failing system
  2. Fall back to dropping trees inline on the current thread when the channel/spawn fails, trading latency for correctness
  3. Initialize the drop thread eagerly at startup and abort with a clear diagnostic instead of panicking on first snapshot drop
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at crates/language/src/syntax_map.rs:53 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20). Data as JSON: /api/errors/528291dfb62ee9ba. Report an issue: GitHub.