"Commit a new .shader together with its compiled .shader_c, or it fails its first load"
▸ SYMPTOM
You add a brand-new custom .shader, commit only the source, and someone pulls it. On its first in-editor load it errors out with a misleading chain, even though the HLSL is perfectly correct:
On-demand recompile of asset <shader> -> reason: Invalid Dependency Information
WARNING: Failed on-demand recompile
Error loading resource file <shader>_c (ERROR_FILEOPEN: File not found)The confusing part: seconds later the engine's own background compile of the same shader succeeds and writes a valid _c (Done N combos in Nms). So the error looks like a broken shader, but the shader is fine — it's a first-load race.
▸ CAUSE
The engine loads shaders only from the compiled .shader_c, never from source directly. A never-before-compiled shader has no dependency record yet, so the on-demand compile path reports "Invalid Dependency Information" and fails to find the _c — while racing the engine's own background compile, which is what eventually produces the valid _c. The failure you see is the on-demand path losing that race, not a problem with your HLSL.
▸ FIX
Commit the .shader source together with its compiled .shader_c. The shader compiles deterministically in-editor, so the _c is reproducible, and re-saving the shader regenerates it if it ever goes stale. With the _c present, the first load reads it straight away and never hits the on-demand recompile race.
Convention note: .shader_c is tracked in source control; .vmat_c compiled artifacts conventionally are not — only the shader's compiled artifact needs to travel with the source.
Two related traps from the same hunt worth knowing:
- A headless
dotnet buildcompiles C# only — it can never catch a shader problem. Don't treat a green headless build as evidence your shader is good. - The editor's
asset_compiletooling doesn't support shader assets at all. It throws "has no source file" even on a known-good shader, so you can't lean on it to pre-bake the_c. Let the editor compile the shader (open/save it) and commit the resulting_c.
▸ WHY IT WORKS
Shaders are a _c-only load path. Shipping the compiled artifact alongside the source means the first machine to load it already has the exact file the loader wants, so there's no on-demand recompile, no dependency-record cold start, and no race for that first load to lose. Every subsequent edit just re-saves and regenerates the _c deterministically.
- Published