Learn · 8
Debugging
WebGPU fails quietly. It does not throw on a bad pipeline — it discards the command buffer and hands you numbers that are merely wrong. This lesson is the set of questions you can ask the device, and every one of them exists because something here went wrong silently first.
Is this a real GPU?
A headless browser will hand you a software rasterizer, and it is still an adapter,
so nothing throws. Timings measured there belong to the rasterizer, not to this
library. probe() answers before anything is initialised and separates
"the browser has no WebGPU" from "the driver refused".
Did the GPU reject anything?
Validation errors arrive on an event, not as exceptions. The device counts them and keeps the first message, because a broken shader repeats its error on every subsequent dispatch and scrolls the real cause off the screen. A benchmark once reported milliseconds per step while holding an invalid command buffer — that number was not a measurement, it was the wall clock of a model that was not learning.
What is it holding?
Two different questions, so two numbers. memory asks "is this leaking"
and deliberately excludes the pool; pooled asks "how large is the
footprint" and counts what is waiting to be reused. The pool grows when shapes
change — buffers are kept per size, so batch 16's cannot serve batch 32.
Did a gradient actually flow?
The trap that value-comparing tests cannot see: an operation returns the right
numbers and quietly drops the gradient. Both roll and
maskedSelect were cut that way on the GPU path while the golden table
was entirely green. Asking is cheap — run backward and look at whether
.grad arrived at all.
Errors say what torch says
When borch refuses, it refuses with the message torch uses, so the phrase you would paste into a search engine is the same one. That equivalence is tested: 12 error cases and 9 searchable messages.
docs/BOOK.md) under "Seven places where green can be a lie". The device counters
above exist because three of them were found the hard way.