{"record":{"id":"214da82d5b56eb4c","repo":"niri-wm/niri","slug":"missing-gbm","errorCode":null,"errorMessage":"missing gbm","messagePattern":"missing gbm","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/screencasting/pw_utils.rs","lineNumber":1415,"sourceCode":"            alpha,\n            dma_negotiation,\n            ..\n        } = self.state\n        else {\n            trace!(\"pw stream: add_buffer, but not ready yet\");\n            return Ok(false);\n        };\n\n        match dma_negotiation {\n            Some(DmaNegotiation { modifier, .. }) => {\n                trace!(\n                    \"pw stream: add_buffer (dma), size={size:?}, \\\n                     alpha={alpha}, modifier={modifier:?}\"\n                );\n\n                let Some(gbm) = gbm else {\n                    error!(\"add_buffer(dma) without gbm\");\n                    bail!(\"missing gbm\");\n                };\n\n                unsafe {\n                    let spa_buffer = (*buffer).buffer;\n\n                    let fourcc = if alpha {\n                        Fourcc::Argb8888\n                    } else {\n                        Fourcc::Xrgb8888\n                    };\n\n                    let dmabuf = allocate_dmabuf(gbm, size, fourcc, modifier)\n                        .context(\"error allocating dmabuf\")?;\n\n                    let plane_count = dmabuf.num_planes();\n                    assert_eq!((*spa_buffer).n_datas as usize, plane_count);\n\n                    for (i, (fd, (stride, offset))) in","sourceCodeStart":1397,"sourceCodeEnd":1433,"githubUrl":"https://github.com/niri-wm/niri/blob/62c230a662ac913a54fc49c86fda0406da3f3ba9/src/screencasting/pw_utils.rs#L1397-L1433","documentation":"When the pipewire stream negotiates DMA-BUF buffer sharing, on_add_buffer needs a GBM device handle to allocate/import the dmabuf. If the gbm option is None (no GBM device was configured for the stream), DMA-BUF support cannot work and the callback bails with 'missing gbm'.","triggerScenarios":"A screencast session negotiated DMA-BUF param buffers but the stream context was created without a GBM device — i.e. the gbm slot passed into the pw stream state is None when the pipewire stream adds a dma buffer.","commonSituations":"Running on a system without a DRM/GBM device (headless, container without /dev/dri); screencast started before GPU init; configuration disabling GBM while the client still requests DMA-BUF.","solutions":["Initialize and pass the GBM device when constructing the pipewire screencast stream state","Fall back to MemFd (SHM) sharing when gbm is unavailable instead of negotiating DMA-BUF","Ensure /dev/dri devices are accessible in the runtime environment (containers, permissions)"],"exampleFix":"// before\nPwStreamParams { gbm: None, .. }\n// after\nPwStreamParams { gbm: Some(gbm_device.clone()), .. }","handlingStrategy":"fallback","validationCode":"if gbm_device.is_none() {\n    // force MemFd sharing instead of requesting DMA-BUF in pw stream params\n    params.set_sharing_type(DataType::MemFd);\n}","typeGuard":"fn dma_supported(gbm: &Option<GbmDevice>) -> bool { gbm.is_some() }","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"missing gbm\") => {\n        // renegotiate stream with MemFd sharing\n    }\n    other => other?,\n}","preventionTips":["Probe GBM/DRM availability at session start and pick the sharing type accordingly","In containers, mount /dev/dri or disable DMA-BUF negotiation","Log gbm availability when creating the pw stream state"],"tags":["pipewire","dmabuf","gbm","screencast"],"backgroundTag":"missing-dependency","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"}