---
title: Shader diagnostics and fix-its
description: Use these messages as the self-correction map for generated shader code. Prefer fixing the shader/binding shape over suppressing errors.
---

# Shader diagnostics and fix-its



## `VGPU-RESOLVE-MODULE-BINDING`

WGSL modules must be pure helpers. A module may export structs, functions, constants, and types, but it must not declare `@group(...) @binding(...)` variables. Move bindings to the entry shader:

```wgsl
// noise.wgsl
export struct NoiseConfig { seed: u32 }
export fn noise(p: vec2f, cfg: NoiseConfig) -> f32 { return f32(cfg.seed) * 0.0; }
```

```wgsl
// entry.wgsl
import { NoiseConfig, noise } from "./noise.wgsl";
@group(0) @binding(0) var<uniform> cfg: NoiseConfig;
```

## `VGPU-SHADER-SOURCE-INVALID`

main API (vgpu) shader arguments are either a WGSL string or a loader `ShaderSource { version: 1, wgsl }`. If importing `.wgsl` returns a URL/object without `version` and `wgsl`, configure `@vgpu/wgsl/loader-vite`, `@vgpu/wgsl/loader-webpack`, or pass a raw WGSL string.

```text
import shader from "./shader.wgsl";
const draw = draw(gpu, { shader });
```

## Stage storage limits: `VGPU-LIMIT-STORAGE-VERTEX` / `VGPU-LIMIT-STORAGE-FRAGMENT`

**Symptom:** creating a draw reports that the selected vertex or fragment entry uses more storage buffers than the device grants for that stage.

**Cause:** bindings statically reached by the selected entry point count against `maxStorageBuffersInVertexStage` or `maxStorageBuffersInFragmentStage` (falling back to `maxStorageBuffersPerShaderStage` when a stage-specific property is unavailable). Unused declarations and resources used only by another stage do not count.

**Fix:** if the adapter supports it, request the reported count through `init({ requiredLimits: { maxStorageBuffersInVertexStage: count } })` or the fragment sibling. For vertex data, prefer `geometry(gpu, ...)` vertex streams where possible. Otherwise reduce the number of storage buffers reached by that stage. The error detail includes `stage`, `entryPoint`, `count`, `limit`, and the `{ name, group, binding }` bindings that were counted.

## Missing binding: `VGPU-R1-BINDING-NEVER-SET`

Every reflected binding must be set by name or covered by a claimed group. Do not rely on globals or implicit buffers.

```text
const effect = effect(gpu, WGSL);
effect.set({ params: { time: clock(gpu).time }, tex: target.color, samp: sampler(gpu) });
```

## Ownership flip: `VGPU-R1-OWNERSHIP-FLIP`

The first `set()` decides ownership. Plain JS values are lib-owned and updated in place. Resources (`Uniform`, storage, textures, samplers, bind groups) are user-owned. Do not switch the same binding from JS value to resource later.

```text
// Pick one from the start:
wave.set({ params: { time: 0 } });     // lib-owned
// or
wave.set({ params: sharedUniform });   // user-owned
```

## Bool host-shareable layouts

Rule of thumb: treat every bool host-shareable uniform as a `u32` in WGSL. WGSL `bool` is not a stable host-shareable uniform field for JS packing. Use `u32` and encode booleans as `0` or `1`.

```wgsl
struct Params { enabled: u32 }
```

## Bundle stale

`VGPU-R3-BUNDLE-STALE` means a bundle was recorded for a different render signature or an old bind-group/resource identity. A bundle survives resizing the target it draws onto when formats/depth/sample count match; re-record after resource identity changes, including sampling a resized target. Plain JS `set()` updates are safe because buffers are written in place.

## Manual bind-group claims

`VGPU-R4-GROUP-CLAIMED`, `VGPU-R4-GROUP-INCOMPATIBLE`, and `VGPU-R4-GROUP-VALIDATION` all point to manual bind-group ownership. Build the bind group with `draw.layout(group)` or `draw.layout(group, { dynamicOffsets: true })`, call `draw.group(group, bindGroup)`, and send dynamic offsets through `p.draw(draw, { offsets })`.

## Compute aliasing

`VGPU-R1-STORAGE-ALIASING` means a writable storage buffer is bound as both source and destination. Use `pingPongStorage(gpu)` and swap after dispatch.


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)