stride3d/stride · error · InvalidOperationException
SPIRV Magic number not found
Error message
SPIRV Magic number not found
What it means
SpirvBytecode.CreateFromSpan validates that the first 32-bit word of the buffer equals the SPIR-V magic number 0x07230203 before parsing the header. If the data does not start with that magic, the span is not SPIR-V bytecode and parsing would produce garbage, so it throws immediately.
Solutions
- Verify the input actually is SPIR-V: check the first four bytes are 0x03 0x02 0x23 0x07 before calling CreateFromSpan
- Ensure you pass the SPIR-V module itself, not a container or source text; strip any wrapping header first
- Confirm the byte->int cast uses correct endianness (little-endian words) and that no offset shifted the start of the module
Example fix
// before
var bytecode = SpirvBytecode.CreateFromSpan(File.ReadAllBytes("shader.fxc")); // DXBC, not SPIR-V
// after
var bytes = File.ReadAllBytes("shader.spv");
if (bytes.Length >= 4 && bytes[0] == 0x03 && bytes[1] == 0x02 && bytes[2] == 0x23 && bytes[3] == 0x07)
var bytecode = SpirvBytecode.CreateFromSpan(bytes); Defensive patterns
Strategy: validation
Validate before calling
static bool LooksLikeSpirv(ReadOnlySpan<byte> bytes) =>
bytes.Length >= 4 && bytes[0] == 0x03 && bytes[1] == 0x02 && bytes[2] == 0x23 && bytes[3] == 0x07;
if (!LooksLikeSpirv(bytes))
throw new InvalidDataException("Input is not SPIR-V (magic number 0x07230203 missing)."); Type guard
static bool IsSpirvMagic(Span<int> words) => words.Length > 0 && words[0] == 0x07230203;
Try / catch
try
{
var bytecode = SpirvBytecode.CreateFromSpan(span);
}
catch (InvalidOperationException ex) when (ex.Message == "SPIRV Magic number not found")
{
log.Error("Input blob is not SPIR-V bytecode (bad magic); check the source container/format.");
} Prevention
- Verify the first 4 bytes (0x03 0x02 0x23 0x07) before parsing
- Never pass DXBC/GLSL text/container-prefixed blobs to CreateFromSpan
- Persist a format tag alongside cached shaders so SPIR-V blobs are identifiable
- Watch endianness when building the int span on non-little-endian platforms
When it happens
Trigger: Calling CreateFromSpan(byte[]/Span<byte>) or CreateFromSpan(Span<int>) with data that is not SPIR-V: raw HLSL/GLSL text, a D3D bytecode blob (DXBC), a truncated buffer, a byte-order/endian-mangled blob, or an offset into a larger file that skips the header.
Common situations: Passing compiled DXBC instead of SPIR-V; passing shader source text; reading a shader cache file with a container header still attached; a save/load pipeline that trims or re-orders bytes; platform endianness differences when filling the int span.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- SPIRV Magic number not found
- 64bit integers
- Binary operator not supported for element type
- BuildInheritanceListWithoutSelf: OpMixinInheritSDSL…
- bytecode
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/0e77fcf25aafee60.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Spirv/Buffers/SpirvBytecode.cs:40
bound = index + 1;
}
return new SpirvHeader("1.4", 0, bound);
}
public Span<byte> ToSpan()
{
return CreateBytecodeFromBuffers(Header, false, Buffer);
}
public static SpirvBytecode CreateFromSpan(Span<byte> span)
{
return CreateFromSpan(MemoryMarshal.Cast<byte, int>(span));
}
public static SpirvBytecode CreateFromSpan(Span<int> span)
{
if (span[0] != Specification.MagicNumber)
throw new InvalidOperationException("SPIRV Magic number not found");
var header = SpirvHeader.Read(span);
return new(header, new SpirvBuffer(span[SpirvHeader.IntSpanSize..]));
}
// Returns a freshly allocated array. Do not back this with ArrayPool/SpanOwner: the caller
// receives a Span that carries no ownership, so a pooled buffer would be returned to the pool
// by the finalizer and reused while the span is still in use, silently corrupting the bytecode
// (e.g. another shader's OpCapability bleeding into vkCreateShaderModule input).
public static Span<int> CreateSpanFromBuffers(SpirvHeader header, bool computeBounds, params Span<SpirvBuffer> buffers)
{
int instructionsMemorySize = 0;
var bound = header.Bound;
foreach (var buffer in buffers)
{
foreach (var i in buffer)
{View on GitHub (pinned to 96fad776d2)