stride3d/stride · error · InvalidOperationException
Shader ' ' was loaded without a source hash (missing…
Error message
Shader '{name}' was loaded without a source hash (missing OpSourceHashSDSL). What it means
LoadExternalBuffer delegates to the inner loader and then asserts that a file-backed shader always carries a non-empty source hash. A zero ObjectId means the shader was compiled or cached without its OpSourceHashSDSL instruction, which would make the effect appear stale and be recompiled on every run. The mixer treats that as an invalid input buffer and throws InvalidOperationException.
Solutions
- Recompile the shader (delete the stale cache entry and regenerate it) with source-hash emission enabled so OpSourceHashSDSL is embedded.
- Check the code path that writes the external buffer and ensure emitSourceHash: true is passed to the compiler.
- If you control the loader, verify the buffer's hash on disk (or with an offline tool) before handing it to LoadExternalBuffer.
Example fix
// before
sdslc.Compile(filename, text, hash, macros, log, out buffer, new() { EmitSourceHash = false });
// after
sdslc.Compile(filename, text, hash, macros, log, out buffer, new() { EmitSourceHash = true }); Defensive patterns
Strategy: validation
Validate before calling
// check the buffer's hash before handing it to the mixer var loader = ...; loader.LoadExternalBuffer(name, defines, out var bytecode, out var hash, out _); // hash was checked internally; pre-validate cache files instead: bool HasSourceHash(ObjectId hash) => hash != ObjectId.Empty;
Try / catch
try { mixer.LoadExternalBuffer(name, defines, out var bc, out var hash, out var cached); }
catch (InvalidOperationException ex) when (ex.Message.Contains("OpSourceHashSDSL")) {
RecompileShader(name, defines); // regenerate with EmitSourceHash = true
} Prevention
- Always compile/cached-emit shaders with EmitSourceHash = true.
- Purge shader caches when upgrading the compiler version.
- Spot-check cached buffers for OpSourceHashSDSL after build pipeline changes.
When it happens
Trigger: Calling ShaderMixer.LoadExternalBuffer(name, defines, ...) when the SPIR-V/SDSL buffer on disk or in cache was produced with source-hash emission disabled (emitSourceHash=false) or by an older compiler that did not emit OpSourceHashSDSL, so the returned hash is ObjectId.Empty.
Common situations: Mixing shader binaries produced by a different compiler version; cache entries written before OpSourceHashSDSL emission was introduced; a build step that compiles shaders with hashing turned off for speed.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- 64bit integers
- Binary operator not supported for element type
- BuildInheritanceListWithoutSelf: OpMixinInheritSDSL…
- Can't add type
- Can't cast between array of different sizes
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/42f194e9a0fe56c6.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs:1397
/// </summary>
/// <remarks>Expects hash to be stored.</remarks>
public IShaderCache Cache => inner.Cache;
public GenericShaderCache GenericCache => inner.GenericCache;
public HashSourceCollection Sources { get; } = new();
public bool Exists(string name) => inner.Exists(name);
public bool LoadExternalFileContent(string name, out string filename, out string code, out ObjectId hash)
=> inner.LoadExternalFileContent(name, out filename, out code, out hash);
public bool LoadExternalBuffer(string name, ReadOnlySpan<ShaderMacro> defines, out ShaderBuffers bytecode, out ObjectId hash, out bool isFromCache)
{
var result = inner.LoadExternalBuffer(name, defines, out bytecode, out hash, out isFromCache);
// A file-backed shader always carries a source hash. A zero here means it was compiled or cached
// without its OpSourceHashSDSL, which would make its effect obsolete (recompiled) on every run.
if (hash == ObjectId.Empty)
throw new InvalidOperationException($"Shader '{name}' was loaded without a source hash (missing OpSourceHashSDSL).");
if (!Sources.ContainsKey(name))
Sources.Add(name, hash);
return result;
}
public bool LoadExternalBuffer(string name, string? filename, string code, ReadOnlySpan<ShaderMacro> defines, out ShaderBuffers bytecode, out ObjectId hash, out bool isFromCache)
=> inner.LoadExternalBuffer(name, filename, code, defines, out bytecode, out hash, out isFromCache);
public bool SuppressSourceHash { get => inner.SuppressSourceHash; set => inner.SuppressSourceHash = value; }
}
View on GitHub (pinned to 96fad776d2)