niri-wm/niri · error
invalid buffer format or size
Error message
invalid buffer format or size
What it means
After mapping the format, render_to_shm verifies the buffer's actual metadata (format, width, height) matches the output mode size derived from damage_tracker.mode(). If the buffer's dimensions or format disagree with the logical output size, rendering is aborted with this error to avoid out-of-bounds writes or corrupted frames.
Solutions
- Reallocate the shm buffer to match damage_tracker.mode().try_into().unwrap() (size.w x size.h) and the same format before rendering
- Re-run buffer allocation on output mode/scale change events instead of caching buffers
- Check buffer_data.format equals the wl_shm::Format you pass in
Example fix
// before (buffer allocated before resize) let buffer = create_shm_buffer(old_width, old_height, wl_shm::Format::Argb8888); // after (reallocate on mode change) let (size, _, _) = damage_tracker.mode().try_into()?; let buffer = create_shm_buffer(size.w, size.h, wl_shm::Format::Argb8888);
Defensive patterns
Strategy: validation
Validate before calling
let (size, _, _) = damage_tracker.mode().try_into()?;
if buffer_data.width != size.w || buffer_data.height != size.h || buffer_data.format != format {
// reallocate the buffer to (size.w, size.h, format) before rendering
} Try / catch
match render_to_shm(...) {
Err(e) if e.to_string().contains("invalid buffer format or size") => {
// drop cached buffers, reallocate at current mode size, retry
}
other => other?,
} Prevention
- Reallocate capture buffers on every output mode/scale/transform change event
- Never cache shm buffers across resize; key buffers by (w,h,format)
- Compare buffer metadata against the current mode before each render
When it happens
Trigger: Passing a shm buffer sized differently from damage_tracker.mode()'s logical size (w,h), or a buffer whose buffer_data.format differs from the wl_shm::Format being rendered with — typically a stale or wrongly allocated buffer after an output resize/mode change.
Common situations: Output resolution or scale changed while capture buffers were allocated for the old size; client-allocated buffers with wrong stride/dimensions; mismatched format between the requested wl_shm::Format and the pool's actual format.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of niri-wm/niri@62c230a662 (2026-09-19).
Data as JSON: /api/errors/fa3998f32103975a.
Report an issue: GitHub.
Appendix: source
Thrown at src/render_helpers/mod.rs:348
renderer: &mut GlesRenderer,
damage_tracker: &mut OutputDamageTracker,
buffer: &WlBuffer,
format: wl_shm::Format,
elements: &[impl RenderElement<GlesRenderer>],
states: RenderElementStates,
) -> anyhow::Result<()> {
let _span = tracy_client::span!();
// The pointer and length are the client's entire pool, which may hold other
// buffers besides this one... buffer_data is the one we want.
shm::with_buffer_contents_mut(buffer, |pool, pool_len, buffer_data| {
let (size, _scale, _transform) = damage_tracker.mode().try_into().unwrap();
let fourcc = match format {
wl_shm::Format::Xrgb8888 => Fourcc::Xrgb8888,
wl_shm::Format::Argb8888 => Fourcc::Argb8888,
_ => bail!("unsupported shm format: {format:?}"),
};
ensure!(
// The buffer prefers pixels in little endian ...
buffer_data.format == format
&& buffer_data.width == size.w
&& buffer_data.height == size.h,
"invalid buffer format or size"
);
// The client chooses the stride and may pad rows, so only the first
// row_len bytes can be used here.
let row_len = size.w as usize * 4;
let height = size.h as usize;
let offset = usize::try_from(buffer_data.offset).context("negative buffer offset")?;
let stride = usize::try_from(buffer_data.stride).context("negative buffer stride")?;
// This should have already been validated by wl_shm, and a pool can
// only grow, but check again just in case.
let end = stride
.checked_mul(height.saturating_sub(1))View on GitHub (pinned to 62c230a662)