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

  1. Renegotiate the pipewire stream parameters (size/stride) when the output mode or scale changes
  2. Set the pw stream video size to exactly damage_tracker.mode()'s logical size with SHM_BYTES_PER_PIXEL bytes per pixel
  3. 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

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


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)