gfx-rs/wgpu · error

vkFreeDescriptorSets error: {err}, please report this error

Error message

vkFreeDescriptorSets error: {err}, please report this error

What it means

When destroying a descriptor set, the Vulkan backend calls vkFreeDescriptorSets, which is only expected to fail with VK_ERROR_UNKNOWN or a validation-layer error. wgpu-hal does not yet propagate errors from destroy paths, so any unexpected result triggers this panic asking the user to file a bug. It typically indicates a driver bug, double-free/invalid handle, or a validation failure.

Source

Thrown at wgpu-hal/src/vulkan/descriptor.rs:239

            bucket_key: key,
            pool_index,
        })
    }

    pub unsafe fn free(&mut self, device: &ash::Device, set: DescriptorSet) {
        let bucket = self.buckets.get_mut(&set.bucket_key).unwrap();
        let pool = bucket.pools.get_mut(set.pool_index).unwrap();

        let result =
            unsafe { device.free_descriptor_sets(pool.raw, core::slice::from_ref(&set.raw())) };
        if let Err(err) = result {
            // vkFreeDescriptorSets is documented to return:
            // - VK_ERROR_UNKNOWN
            // - VK_ERROR_VALIDATION_FAILED (we shouldn't encounter this one)
            // wgpu-hal doesn't currently report errors in destroy functions.
            // Panic here for now. It might be ok to ignore the error but the
            // proper solution would probably be to lose the device.
            panic!("vkFreeDescriptorSets error: {err}, please report this error");
        }

        pool.available += 1;
        bucket.available_sets += 1;
        bucket.allocated_sets -= 1;
        if set.bucket_key.update_after_bind {
            self.update_after_bind_descriptors_in_all_pools -= set.bucket_key.counts.total();
        }

        // Do not immediately destroy empty pools since they might have
        // been recently created.
        // Destroy a pool only if it's empty and we have 1/4th its capacity
        // in other pools.
        // Note that this logic will never destroy the last pool.
        let pool = bucket.pools.last().unwrap();
        if pool.available == pool.capacity
            && bucket.available_sets - pool.capacity > pool.capacity / 4
        {

View on GitHub (pinned to 3e11ff59bf)

Solutions

  1. Reproduce with Vulkan validation layers enabled and inspect the validation message to find the underlying API misuse.
  2. Check whether a recent driver update/downgrade changes the behavior (likely driver bug).
  3. Report the error to the wgpu issue tracker as the message instructs, including the vk::Result value, driver, and GPU.
  4. As a workaround, verify no custom pool/destroy logic frees descriptor sets before wgpu does.
Defensive patterns

Strategy: try-catch

Try / catch

// This is a panic inside wgpu-hal's destroy path; catch it process-wide.
std::panic::catch_unwind(|| drop(descriptor_set)); // last resort; resource is likely invalid
// Preferred: enable Vulkan validation layers in dev to catch the misuse earlier:
// VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation

Prevention

When it happens

Trigger: Freeing a descriptor set at destroy time where `vkFreeDescriptorSets` returns a non-SUCCESS result, e.g. after the descriptor pool was already destroyed or the set handle became invalid.

Common situations: Driver bugs on certain GPUs; running under a validation layer reporting API misuse; resource-destroy ordering problems; corrupted device state after a prior device loss.

Related errors


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