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:

  1. An explicit --rhi-validate or --no-rhi-validate wins.
  2. Else the saved Vulkan validation setting.
  3. 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.

In this section
Topics
howto rendering rhi vulkan validation diagnostics