niri-wm/niri · error

missing gbm

Error message

missing gbm

What it means

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'.

Solutions

  1. Initialize and pass the GBM device when constructing the pipewire screencast stream state
  2. Fall back to MemFd (SHM) sharing when gbm is unavailable instead of negotiating DMA-BUF
  3. Ensure /dev/dri devices are accessible in the runtime environment (containers, permissions)

Example fix

// before
PwStreamParams { gbm: None, .. }
// after
PwStreamParams { gbm: Some(gbm_device.clone()), .. }
Defensive patterns

Strategy: fallback

Validate before calling

if gbm_device.is_none() {
    // force MemFd sharing instead of requesting DMA-BUF in pw stream params
    params.set_sharing_type(DataType::MemFd);
}

Type guard

fn dma_supported(gbm: &Option<GbmDevice>) -> bool { gbm.is_some() }

Try / catch

match result {
    Err(e) if e.to_string().contains("missing gbm") => {
        // renegotiate stream with MemFd sharing
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of niri-wm/niri@62c230a662 (2026-09-19). Data as JSON: /api/errors/214da82d5b56eb4c. Report an issue: GitHub.

Appendix: source

Thrown at src/screencasting/pw_utils.rs:1415

            alpha,
            dma_negotiation,
            ..
        } = self.state
        else {
            trace!("pw stream: add_buffer, but not ready yet");
            return Ok(false);
        };

        match dma_negotiation {
            Some(DmaNegotiation { modifier, .. }) => {
                trace!(
                    "pw stream: add_buffer (dma), size={size:?}, \
                     alpha={alpha}, modifier={modifier:?}"
                );

                let Some(gbm) = gbm else {
                    error!("add_buffer(dma) without gbm");
                    bail!("missing gbm");
                };

                unsafe {
                    let spa_buffer = (*buffer).buffer;

                    let fourcc = if alpha {
                        Fourcc::Argb8888
                    } else {
                        Fourcc::Xrgb8888
                    };

                    let dmabuf = allocate_dmabuf(gbm, size, fourcc, modifier)
                        .context("error allocating dmabuf")?;

                    let plane_count = dmabuf.num_planes();
                    assert_eq!((*spa_buffer).n_datas as usize, plane_count);

                    for (i, (fd, (stride, offset))) in

View on GitHub (pinned to 62c230a662)