zed-industries/zed · error
Stream has ended, callback cant hold the lock
Error message
Stream has ended, callback cant hold the lock
What it means
Asserts in write_out that samples.try_lock() succeeds because the capture stream must have ended before encoding is finalized. Firing means audio callbacks may still be running concurrently — the stream wasn't stopped/dropped before finish() called write_out — so taking the sample buffer would race with the callback.
Source
Thrown at crates/livekit_client/src/record.rs:90
},
|err| log::error!("error capturing audio track: {:?}", err),
Some(Duration::from_millis(100)),
)
.context("failed to build input stream")?;
stream.play()?;
Ok(stream)
}
fn write_out(
samples: Arc<Mutex<Vec<i16>>>,
config: cpal::SupportedStreamConfig,
path: &Path,
) -> Result<()> {
let samples = std::mem::take(
&mut *samples
.try_lock()
.expect("Stream has ended, callback cant hold the lock"),
);
let samples: Vec<f32> = SampleTypeConverter::<_, f32>::new(samples.into_iter()).collect();
let mut samples = SamplesBuffer::new(
NonZero::new(config.channels()).expect("config channel is never zero"),
NonZero::new(config.sample_rate()).expect("config sample_rate is never zero"),
samples,
);
match rodio::wav_to_file(&mut samples, path) {
Ok(_) => Ok(()),
Err(e) => Err(anyhow::anyhow!("Failed to write wav file: {}", e)),
}
}
View on GitHub (pinned to f4178619ac)
Solutions
- Drop the cpal Stream before calling write_out/finish to guarantee callbacks ceased
- Replace try_lock().expect with handling for TryLockError if the lifecycle cannot be strictly ordered
- Add an explicit stop/pause on the stream and join/sleep until the last callback completes
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/livekit_client/src/record.rs:90 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/3d4eac39597daffd.
Report an issue: GitHub.