gfx-rs/wgpu · error

wgpu-hal invariant was violated (usage error): {txt}

Error message

wgpu-hal invariant was violated (usage error): {txt}

What it means

hal_usage_error is wgpu-hal's marker panic for a violated HAL invariant: wgpu-core passed arguments to the backend that the WebGPU validation layer should have rejected (or that are impossible per the API contract). It signals a usage error reaching the backend, i.e. a bug in wgpu-core's validation or a broken unsafe caller — not a runtime environment problem. The message includes `txt` describing which invariant was broken.

Source

Thrown at wgpu-hal/src/lib.rs:511

    }
}

#[cfg(any(dx12, vulkan))]
impl From<AllocationSizes> for gpu_allocator::AllocationSizes {
    fn from(value: AllocationSizes) -> gpu_allocator::AllocationSizes {
        gpu_allocator::AllocationSizes::new(
            value.min_device_memblock_size,
            value.min_host_memblock_size,
        )
        .with_max_device_memblock_size(value.max_device_memblock_size)
        .with_max_host_memblock_size(value.max_host_memblock_size)
    }
}

#[allow(dead_code, reason = "may be unused on some platforms")]
#[cold]
fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {
    panic!("wgpu-hal invariant was violated (usage error): {txt}")
}

#[allow(dead_code, reason = "may be unused on some platforms")]
#[cold]
fn hal_internal_error<T: fmt::Display>(txt: T) -> ! {
    panic!("wgpu-hal ran into a preventable internal error: {txt}")
}

#[derive(Clone, Debug, Eq, PartialEq, Error)]
pub enum ShaderError {
    #[error("Compilation failed: {0:?}")]
    Compilation(String),
    #[error(transparent)]
    Device(#[from] DeviceError),
}

#[derive(Clone, Debug, Eq, PartialEq, Error)]
pub enum PipelineError {

View on GitHub (pinned to 3e11ff59bf)

Solutions

  1. If you use the wgpu Rust API: this is a wgpu bug — reduce to a minimal reproducer and file an issue at github.com/gfx-rs/wgpu with the panic text.
  2. If you embed wgpu-hal directly: validate arguments against the backend contract before calling hal functions; the panic is by-design protection.
  3. Check for resource destruction races: keep resources alive until submission fences complete (hold Arc/refs or use on_submitted_work_done).
  4. Pin to a wgpu version known-good for your workload or apply the fix from a newer release if the issue is already fixed upstream.

Example fix

// before (hal embedder)
unsafe { cmd_buf.set_bind_group(layout, group, &offsets) }; // offsets unchecked
// after
assert!(offsets.len() == layout.dynamic_offset_count as usize);
assert!(offsets.iter().all(|o| *o < group_binding_size));
unsafe { cmd_buf.set_bind_group(layout, group, &offsets) };
Defensive patterns

Strategy: try-catch

Validate before calling

// embedders: pre-validate hal arguments
assert_eq!(offsets.len(), layout.dynamic_count as usize);
assert!(resource.is_alive());

Type guard

fn valid_dynamic_offsets(offsets: &[u32], layout: &HalBindGroupLayout) -> bool {
    offsets.len() == layout.dynamic_count as usize
}

Try / catch

std::panic::catch_unwind(|| unsafe {
    hal_cmd.set_bind_group(layout, group, offsets)
}).map_err(|p| format!("hal usage error: {p:?}"))

Prevention

When it happens

Trigger: Calling wgpu-hal APIs directly with invalid arguments (custom integrations like Deno/Firefox embedders); hitting a wgpu-core validation gap where an invalid resource/state combination is forwarded to the backend, e.g. bad bind group slot, out-of-range dynamic offsets, mismatched buffer usage at map time.

Common situations: Embedders bypassing wgpu-core; newly added wgpu-core features with incomplete validation; race conditions where a resource was destroyed while still referenced by an in-flight submission; reporting bugs upstream when this fires during ordinary wgpu API use.

Related errors


AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03). Data as JSON: /api/errors/5423b95b06638e01. Report an issue: GitHub.