{"record":{"id":"e0a656264e46bb4b","repo":"niri-wm/niri","slug":"invalid-buffer-size","errorCode":null,"errorMessage":"invalid buffer size","messagePattern":"invalid buffer size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/screencasting/pw_utils.rs","lineNumber":1890,"sourceCode":"        // Fill the metadata now that everything succeeded.\n        bitmap_meta.size.width = size.w as _;\n        bitmap_meta.size.height = size.h as _;\n        bitmap_meta.stride = size.w * CURSOR_BPP as i32;\n    }\n}\n\nfn render_to_shmbuf(\n    renderer: &mut GlesRenderer,\n    damage_tracker: &mut OutputDamageTracker,\n    buffer: &Shmbuf,\n    fourcc: Fourcc,\n    elements: &[impl RenderElement<GlesRenderer>],\n    states: RenderElementStates,\n) -> anyhow::Result<()> {\n    let _span = tracy_client::span!();\n    let (size, _scale, _transform) = damage_tracker.mode().try_into().unwrap();\n    let expected_size = size.w as usize * size.h as usize * SHM_BYTES_PER_PIXEL;\n    ensure!(\n        buffer.layout.size_usize() == expected_size,\n        \"invalid buffer size\"\n    );\n\n    let mapping =\n        render_and_download_with_damage(renderer, damage_tracker, fourcc, elements, states)?;\n\n    let bytes = renderer\n        .map_texture(&mapping)\n        .context(\"error mapping texture\")?;\n\n    unsafe {\n        let buf = mmap(\n            std::ptr::null_mut(),\n            buffer.layout.size_usize(),\n            ProtFlags::READ | ProtFlags::WRITE,\n            MapFlags::SHARED,\n            buffer.fd.clone(),","sourceCodeStart":1872,"sourceCodeEnd":1908,"githubUrl":"https://github.com/niri-wm/niri/blob/62c230a662ac913a54fc49c86fda0406da3f3ba9/src/screencasting/pw_utils.rs#L1872-L1908","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (negotiation)\nlet stride = output.size().w * 4; // uses physical size\n// after\nlet (size, _, _) = damage_tracker.mode().try_into()?;\nlet stride = size.w * SHM_BYTES_PER_PIXEL;\nparams.set_size(size.w, size.h).set_stride(stride);","handlingStrategy":"validation","validationCode":"let (size, _, _) = damage_tracker.mode().try_into()?;\nlet expected = size.w as usize * size.h as usize * SHM_BYTES_PER_PIXEL;\nif buffer.layout.size_usize() != expected {\n    // renegotiate pw stream params with size (size.w, size.h) and stride size.w * SHM_BYTES_PER_PIXEL\n}","typeGuard":null,"tryCatchPattern":"match render_to_shmbuf(...) {\n    Err(e) if e.to_string().contains(\"invalid buffer size\") => {\n        // trigger stream renegotiation / recreate screencast session\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["pipewire","buffer-size","screencast"],"backgroundTag":"shape-mismatch","analyzedSha":"62c230a662ac913a54fc49c86fda0406da3f3ba9","analyzedAt":"2026-09-19T19:48:44.526Z","contentChangedAt":"2026-09-19T19:48:44.526Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}