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
- Check that each permit's job_cost is added exactly once to total_job_cost
- Look for the 'job cost underflow' warning to identify the unpaired allocation
- 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
- Never clone or duplicate SearchPermit; each cost must be added once
- Treat the 'job cost underflow' warning as a bug signal, not noise
- Prefer plain subtraction + debug_assert over fetch_update when contention is low
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
- lock should not be poisoned
- lock should not be poisoned
- node not found in pending
- OTP logs or traces do not support VRL transforms
- `doc_batch` should not be empty
AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08).
Data as JSON: /api/errors/92735b88ce08858b.
Report an issue: GitHub.