Run with the Vulkan validation layer
The Khronos validation layer checks every Vulkan call the renderer makes
against the specification and reports each violation with a VUID- code.
It is the tool that turns a device loss into a named cause. This guide
tells you how to enable it, where to get it on each platform, how to read
what it prints, and how to ship it with a build.
Enable it
One switch reaches every Vulkan instance the process creates: the window, the thumbnail workers, the export jobs, the paint preview, and the test suites.
./hub --rhi-validate
A debug build has it on by default. --no-rhi-validate turns it off. When
both are given, --no-rhi-validate wins.
The layer is not an environment variable. Hub also has one setting for its own window: Vulkan validation in the Diagnostics category of the paint settings. Hub decides in this order:
- An explicit
--rhi-validateor--no-rhi-validatewins. - Else the saved Vulkan validation setting.
- Else the build type: on in a debug build, off in a release build.
The setting reaches only the window's instance, and it applies at the next start. The offscreen instances (thumbnail workers, export jobs, test suites) validate only when a flag asks for it.
Confirm that it is running
Look for one of these lines in the log at startup:
createOffscreenVulkanInstance: VK_LAYER_KHRONOS_validation enabled
createOffscreenVulkanInstance: enableValidation=true but VK_LAYER_KHRONOS_validation not installed — skipping layer
createOffscreenVulkanInstance: validation requested but NO Vulkan platform is available
Only the first line means that the layer measures anything. A run that prints the second or third line and reports no errors did not validate. Do not record it as a clean result.
On the OpenGL backend the switch does nothing. The log says so:
validation requested but GL backend in use — ignored
Read the output
Each violation is one message with a VUID- code:
Validation layer: Validation Error: [ VUID-vkCmdDraw-None-02699 ] ...
Search the code on the Vulkan specification site. The text after the code names the object and the call. Attach the first message that appears before the problem to a bug report, with the GPU and driver line from the startup banner.
The build carries the layer
Since 2026-09-25 the tree builds VK_LAYER_KHRONOS_validation itself, on
every platform, from a pinned upstream tree (src/libs/libvulkanvalidation,
render-fault-tolerance Phase 4). Every installed application has the layer
beside it in <binary directory>/vulkan/explicit_layer.d/, and the
application hands that directory to the loader before it creates an
instance. Nothing needs to be installed on the machine. The feature is
project.wantVulkanValidationLayer (default on; vulkanValidationLayer in
the local feature overrides). The first build of a fresh tree fetches the
sources: build the vvl-source and vul-source products, then run
qbs resolve --force-probe-execution, the same two-step LLVM uses.
Check what the loader offers from that directory, on any platform:
VK_LAYER_PATH=<binary directory>/vulkan/explicit_layer.d kiln install --list-layers
kiln install --list-layers loads the loader that the graphics driver
installs and asks it for its instance layers. It writes one name on each
line. With a name, kiln install --list-layers VK_LAYER_KHRONOS_validation
exits 0 if the loader offers the layer and 1 if it does not. The shell sets
VK_LAYER_PATH for kiln, and the loader in kiln reads it. kiln itself reads
no environment variable, so it does not print them: print them with the
shell when a layer is missing.
The layer reports the spec version of the tree's pin (1.4.357 on 2026-09-25), which tells it apart from a system copy.
Use a system layer instead
The application also finds a layer in the system locations the loader searches, so a developer machine with the feature off, or a build that predates it, uses the platform's own copy.
Linux
Debian and Ubuntu:
sudo apt install vulkan-validationlayers
This installs the manifest at
/usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json and
the library under /usr/lib/<triple>/. Fedora: vulkan-validation-layers.
Arch: vulkan-validation-layers. Check with:
vulkaninfo --summary | grep VK_LAYER_KHRONOS_validation
Windows
Install the LunarG Vulkan SDK from https://vulkan.lunarg.com/. The
installer registers the layer under
HKLM\SOFTWARE\Khronos\Vulkan\ExplicitLayers. Check with:
vulkaninfoSDK --summary
Without the SDK, ask the loader directly. This needs a copy of kiln
with its Qt libraries, and the loader the graphics driver installs:
kiln install --list-layers VK_LAYER_KHRONOS_validation
Do not rely on VK_LAYER_PATH or VK_ADD_LAYER_PATH on Windows. The
loader ignores both for a process it considers secure. A process started
over SSH on this project's Windows test machine was one. Register a
manifest in the registry instead:
kiln install --register-layer <bin dir>\vulkan\explicit_layer.d
kiln writes the absolute path of the manifest as a value under
SOFTWARE\Khronos\Vulkan\ExplicitLayers, with DWORD 0 as its data. The
default is HKEY_CURRENT_USER, which needs no elevation. The loader reads
that key and the same key of HKEY_LOCAL_MACHINE. The loader documentation
says that it reads HKEY_CURRENT_USER only for a process without
administrative rights. For an elevated process, register for every user with
--all-users, which writes HKEY_LOCAL_MACHINE and needs an elevated
command prompt. kiln removes each registration whose manifest no longer
exists, and refuses a manifest that does not name its library as
./<library>. Add --unregister-layer to remove the bundle's own value.
On another system, --register-layer exits 2 and does nothing.
macOS
Install the LunarG Vulkan SDK for macOS. The layer library is
libVkLayer_khronos_validation.dylib under the SDK's lib/ directory,
with the manifest under share/vulkan/explicit_layer.d/. The SDK's
setup-env.sh adds the manifest directory to the loader's search path for
the shell it runs in.
Android
The loader searches the application's native library directory for
libVkLayer_khronos_validation.so. Put the prebuilt library for each ABI
from the Vulkan-ValidationLayers release page into the APK's jniLibs.
The application must be debuggable, or the layer must be enabled with
adb shell settings put global enable_gpu_debug_layers 1 and
gpu_debug_layers VK_LAYER_KHRONOS_validation for the package.
Ship a foreign layer with a build
The built layer above is the normal case. A build with the feature off can
still carry somebody else's layer. Name the upstream manifest and its library
in install.layer_bundle in .kiln.local, then lay out the install tree:
# .kiln.local
install.layer_bundle = /usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json /usr/lib/x86_64-linux-gnu/libVkLayer_khronos_validation.so
kiln build --install
kiln copies the library to <binary directory>/vulkan/explicit_layer.d/
and writes the manifest beside it with its library_path changed to
./<library>, relative to the manifest. A manifest that names the library
without a path does not load from a bundle. When validation is requested, the
application hands that directory to the loader before it creates an
instance. The test suite testRhiOffscreenBootstrap proves this layout
loads from its own directory alone on Linux.
install.layer_bundle also takes one folder that holds a layer laid out so
already. For a qbs build, give such a folder to
project.vulkanValidationLayerBundleDir; the vulkan/explicit_layer.d
folder of a kiln install tree is one.
The bundle is one directory per platform. Make it on a machine of that
platform, from the sources in the table above. On Windows the install
step must also register the manifest, because the loader ignores the
directory for a secure process: run kiln install --register-layer with
the installed bundle directory after the install. On Android the layer goes
into jniLibs and needs no manifest.
Verified on Windows 2026-09-23 on the project's test machine: the bundle
made by the script from a Khronos layer DLL (Steam's copy, 1.3.280, since
the SDK was not installed there), registered by the script, is offered by
the loader; unregistered, it is not. list-instance-layers.py was the
witness. Since 2026-09-25 the built layer replaces that bundle on the
next Windows build; the registration then points at the installed
bin\vulkan\explicit_layer.d, and only an elevated or SSH-launched
process needs it. Since script-ports Phase 12 (2026-10-11), kiln install
does what the three scripts did: --list-layers, install.layer_bundle and
--register-layer. The Windows run of kiln install is not yet verified.