{"record":{"id":"fa3998f32103975a","repo":"niri-wm/niri","slug":"invalid-buffer-format-or-size","errorCode":null,"errorMessage":"invalid buffer format or size","messagePattern":"invalid buffer format or size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/render_helpers/mod.rs","lineNumber":348,"sourceCode":"    renderer: &mut GlesRenderer,\n    damage_tracker: &mut OutputDamageTracker,\n    buffer: &WlBuffer,\n    format: wl_shm::Format,\n    elements: &[impl RenderElement<GlesRenderer>],\n    states: RenderElementStates,\n) -> anyhow::Result<()> {\n    let _span = tracy_client::span!();\n    // The pointer and length are the client's entire pool, which may hold other\n    // buffers besides this one... buffer_data is the one we want.\n    shm::with_buffer_contents_mut(buffer, |pool, pool_len, buffer_data| {\n        let (size, _scale, _transform) = damage_tracker.mode().try_into().unwrap();\n        let fourcc = match format {\n            wl_shm::Format::Xrgb8888 => Fourcc::Xrgb8888,\n            wl_shm::Format::Argb8888 => Fourcc::Argb8888,\n            _ => bail!(\"unsupported shm format: {format:?}\"),\n        };\n\n        ensure!(\n            // The buffer prefers pixels in little endian ...\n            buffer_data.format == format\n                && buffer_data.width == size.w\n                && buffer_data.height == size.h,\n            \"invalid buffer format or size\"\n        );\n\n        // The client chooses the stride and may pad rows, so only the first\n        // row_len bytes can be used here.\n        let row_len = size.w as usize * 4;\n        let height = size.h as usize;\n        let offset = usize::try_from(buffer_data.offset).context(\"negative buffer offset\")?;\n        let stride = usize::try_from(buffer_data.stride).context(\"negative buffer stride\")?;\n\n        // This should have already been validated by wl_shm, and a pool can\n        // only grow, but check again just in case.\n        let end = stride\n            .checked_mul(height.saturating_sub(1))","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/niri-wm/niri/blob/62c230a662ac913a54fc49c86fda0406da3f3ba9/src/render_helpers/mod.rs#L330-L366","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (buffer allocated before resize)\nlet buffer = create_shm_buffer(old_width, old_height, wl_shm::Format::Argb8888);\n// after (reallocate on mode change)\nlet (size, _, _) = damage_tracker.mode().try_into()?;\nlet buffer = create_shm_buffer(size.w, size.h, wl_shm::Format::Argb8888);","handlingStrategy":"validation","validationCode":"let (size, _, _) = damage_tracker.mode().try_into()?;\nif buffer_data.width != size.w || buffer_data.height != size.h || buffer_data.format != format {\n    // reallocate the buffer to (size.w, size.h, format) before rendering\n}","typeGuard":null,"tryCatchPattern":"match render_to_shm(...) {\n    Err(e) if e.to_string().contains(\"invalid buffer format or size\") => {\n        // drop cached buffers, reallocate at current mode size, retry\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["shm","buffer-size","screencopy"],"backgroundTag":"invalid-argument-value","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"}