quickwit-oss/quickwit · warning

closure always returns Some

Error message

closure always returns Some

What it means

SearchPermit::drop decrements an AtomicU64 total_job_cost using fetch_update with a saturating_sub closure; since that closure always yields Some, the expect can only fire if the CAS failed 32+ times under extreme contention. Separately, the drop warns when more job cost is released than was allocated (underflow detected by comparing job_cost > prev).

Source

Thrown at quickwit/quickwit-search/src/search_permit_provider.rs:496

    fn send_if_still_running(&self, msg: SearchPermitMessage) {
        if let Some(sender) = self.msg_sender.upgrade() {
            sender
                .send(msg)
                // Receiver instance in the event loop is never dropped or
                // closed as long as there is a strong sender reference.
                .expect("Receiver should live longer than sender");
        }
    }
}

impl Drop for SearchPermit {
    fn drop(&mut self) {
        let prev = self
            .total_job_cost
            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
                Some(v.saturating_sub(self.job_cost))
            })
            .expect("closure always returns Some");
        if self.job_cost > prev {
            warn!(
                job_cost = self.job_cost,
                total_job_cost = prev,
                "job cost underflow: more job cost released than allocated"
            );
        }
        // fetch_update returns the previous value, so subtract job_cost to get the new total.
        SEARCHER_NODE_LOAD.set(prev.saturating_sub(self.job_cost) as f64);
        self.send_if_still_running(SearchPermitMessage::Drop {
            memory_size: self.memory_allocation,
            warmup_slot_freed: self.warmup_slot_freed,
        });
    }
}

pub struct SearchPermitFuture(oneshot::Receiver<SearchPermit>);

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Check that each permit's job_cost is added exactly once to total_job_cost
  2. Look for the 'job cost underflow' warning to identify the unpaired allocation
  3. If the expect itself fires, inspect CAS retry loops / very high concurrency and consider fetch_update retry logging
Defensive patterns

Strategy: validation

Validate before calling

// Before dropping a permit, sanity check:
assert!(permit.job_cost <= total_job_cost.load(Ordering::Relaxed), "permit cost exceeds tracked total");

Prevention

When it happens

Trigger: Dropping SearchPermits concurrently from many threads causing repeated CAS failure (theoretical), or a permit carrying a job_cost larger than the recorded total (real underflow, logged as warning).

Common situations: Buggy permit cloning/ownership allowing the same job_cost to be registered twice; permits dropped after total_job_cost was reset.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/92735b88ce08858b. Report an issue: GitHub.