FyroxEngine/Fyrox · critical
Zero duration buffer
Error message
Zero duration buffer: {:?} What it means
A sound source requires a buffer with non-zero playback length; a zero-duration buffer cannot be played or scheduled. GenericSource::set_buffer checks locked_buffer.duration() and panics with the buffer's debug representation when it is Duration::ZERO (note: a failed load returns SoundError::BufferFailedToLoad instead).
Solutions
- Replace the audio file with a real, non-empty asset; verify duration > 0 before use.
- Check the buffer before assigning: if buffer.duration() == Duration::ZERO, skip/replace it instead of calling set_buffer.
- Regenerate or re-export the sound asset and confirm sample count at import time.
- If buffers are built procedurally, return SoundError (or skip) when sample data is empty rather than constructing a zero-length buffer.
Example fix
// before
source.set_buffer(Some(empty_buffer)); // panics: duration == 0
// after
if buffer.duration() > Duration::ZERO {
source.set_buffer(Some(buffer));
} else {
eprintln!("skipping empty audio buffer");
} Defensive patterns
Strategy: validation
Validate before calling
fn playable(buffer: &SoundBuffer) -> bool {
buffer.duration() > Duration::ZERO
}
// only call set_buffer(Some(b)) when playable(&b) Prevention
- Validate audio assets (duration/sample count) in CI at import time.
- Never ship empty placeholder audio files.
- Check buffer duration after loading and before assignment.
- For procedural buffers, guard sample count > 0 before constructing SoundBuffer.
When it happens
Trigger: Calling set_buffer(Some(buffer)) on a sound source (directly or via SoundBuilder::build) with a SoundBuffer whose decoded duration is zero — e.g. a 0-byte or empty audio file loaded successfully into an empty buffer.
Common situations: Empty/truncated audio files (0-sample wav/ogg) shipped with the game; a generator that produced no samples; file corruption or wrong loader producing empty frames; placeholder audio files never filled in.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Malformed bus graph!
- Height data type error
- Texture is not rectangle
- Illegal nine slice position
- Attempt to get reference to resource data while it is…
AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10).
Data as JSON: /api/errors/7435c5dce31ec754.
Report an issue: GitHub.
Appendix: source
Thrown at fyrox-sound/src/source.rs:229
buffer: Option<SoundBufferResource>,
) -> Result<Option<SoundBufferResource>, SoundError> {
self.buf_read_pos = 0.0;
self.playback_pos = 0.0;
// If we already have streaming buffer assigned make sure to decrease use count
// so it can be reused later on if needed.
if let Some(buffer) = self.buffer.clone() {
if let Some(SoundBuffer::Streaming(streaming)) = buffer.state().data() {
streaming.use_count = streaming.use_count.saturating_sub(1);
}
}
if let Some(buffer) = buffer.clone() {
match buffer.state().data() {
None => return Err(SoundError::BufferFailedToLoad),
Some(locked_buffer) => {
if locked_buffer.duration() == Duration::ZERO {
panic!("Zero duration buffer: {:?}", locked_buffer);
}
// Check new buffer if streaming - it must not be used by anyone else.
if let SoundBuffer::Streaming(ref mut streaming) = *locked_buffer {
if streaming.use_count != 0 {
return Err(SoundError::StreamingBufferAlreadyInUse);
}
streaming.use_count += 1;
}
}
}
}
Ok(std::mem::replace(&mut self.buffer, buffer))
}
/// Returns current buffer if any.
pub fn buffer(&self) -> Option<SoundBufferResource> {
self.buffer.clone()View on GitHub (pinned to 76c91aad8e)