niri-wm/niri · error
invalid buffer size
Error message
invalid buffer size
What it means
render_to_shmbuf computes the expected byte size as width * height * SHM_BYTES_PER_PIXEL from the damage tracker's mode and verifies the target pipewire buffer's layout size matches exactly. A mismatch means the stream-negotiated buffer cannot hold a full frame at the current output size, so rendering is refused to prevent overflow or a torn image.
Solutions
- Renegotiate the pipewire stream parameters (size/stride) when the output mode or scale changes
- Set the pw stream video size to exactly damage_tracker.mode()'s logical size with SHM_BYTES_PER_PIXEL bytes per pixel
- Recreate the screencast session instead of reusing buffers after a resize
Example fix
// before (negotiation) let stride = output.size().w * 4; // uses physical size // after let (size, _, _) = damage_tracker.mode().try_into()?; let stride = size.w * SHM_BYTES_PER_PIXEL; params.set_size(size.w, size.h).set_stride(stride);
Defensive patterns
Strategy: validation
Validate before calling
let (size, _, _) = damage_tracker.mode().try_into()?;
let expected = size.w as usize * size.h as usize * SHM_BYTES_PER_PIXEL;
if buffer.layout.size_usize() != expected {
// renegotiate pw stream params with size (size.w, size.h) and stride size.w * SHM_BYTES_PER_PIXEL
} Try / catch
match render_to_shmbuf(...) {
Err(e) if e.to_string().contains("invalid buffer size") => {
// trigger stream renegotiation / recreate screencast session
}
other => other?,
} Prevention
- Listen for output mode/scale changes and renegotiate the pipewire stream immediately
- Derive pw stream size and stride from the same damage_tracker.mode() used at render time
- Verify negotiated buffer size (stride*height) matches w*h*SHM_BYTES_PER_PIXEL in add_buffer
When it happens
Trigger: The pipewire stream's negotiated buffer size does not equal size.w * size.h * SHM_BYTES_PER_PIXEL — e.g. the output mode/scale changed after the stream negotiated its buffers, or the stream negotiated a smaller/larger video size than the logical output size.
Common situations: Output resolution or scale change mid-screencast without stream renegotiation; pw stream params (width/height/stride) set from a stale size; multiplying stride/height instead of w*h*bytes in the negotiation code.
Related errors
- missing gbm
- unknown data type in dequeue_buffer_and_clear
- unknown data type in dequeue_buffer_and_render
- invalid buffer format or size
AI-assisted analysis of niri-wm/niri@62c230a662 (2026-09-19).
Data as JSON: /api/errors/e0a656264e46bb4b.
Report an issue: GitHub.
Appendix: source
Thrown at src/screencasting/pw_utils.rs:1890
// Fill the metadata now that everything succeeded.
bitmap_meta.size.width = size.w as _;
bitmap_meta.size.height = size.h as _;
bitmap_meta.stride = size.w * CURSOR_BPP as i32;
}
}
fn render_to_shmbuf(
renderer: &mut GlesRenderer,
damage_tracker: &mut OutputDamageTracker,
buffer: &Shmbuf,
fourcc: Fourcc,
elements: &[impl RenderElement<GlesRenderer>],
states: RenderElementStates,
) -> anyhow::Result<()> {
let _span = tracy_client::span!();
let (size, _scale, _transform) = damage_tracker.mode().try_into().unwrap();
let expected_size = size.w as usize * size.h as usize * SHM_BYTES_PER_PIXEL;
ensure!(
buffer.layout.size_usize() == expected_size,
"invalid buffer size"
);
let mapping =
render_and_download_with_damage(renderer, damage_tracker, fourcc, elements, states)?;
let bytes = renderer
.map_texture(&mapping)
.context("error mapping texture")?;
unsafe {
let buf = mmap(
std::ptr::null_mut(),
buffer.layout.size_usize(),
ProtFlags::READ | ProtFlags::WRITE,
MapFlags::SHARED,
buffer.fd.clone(),View on GitHub (pinned to 62c230a662)