stride3d/stride · critical · Exception

: Could not parse spirv

Error message

{cross.ContextParseSpirv(context, w, (nuint)Words.Length, &ir)} : Could not parse spirv

What it means

After the context is created, GetEntryPoints parses the stored SPIR-V words via cross.ContextParseSpirv. If the parse fails (invalid magic number, truncated module, unsupported SPIR-V version), the translator throws with the raw Result code and "Could not parse spirv". This means the bytecode buffer handed to SpirvTranslator is not a valid SPIR-V module.

Solutions

  1. Validate the buffer starts with the SPIR-V magic number 0x07230203 and is properly word-aligned before constructing the translator.
  2. Confirm the buffer actually contains SPIR-V (not DXBC/DXIL/other) and was produced by a compatible SPIR-V frontend version.
  3. Re-export/recompile the shader to regenerate a complete, untruncated SPIR-V module; clear possibly corrupt caches.
  4. Check the numeric Result code in the message against SPIRV-Cross parse error codes for the specific cause.

Example fix

// before
var translator = new SpirvTranslator(dxbcBytes); // wrong format
var entries = translator.GetEntryPoints(); // 'Could not parse spirv'
// after
if (BitConverter.ToUInt32(spirvBytes, 0) != 0x07230203u)
    throw new InvalidDataException("Not SPIR-V");
var translator = new SpirvTranslator(spirvBytes);
var entries = translator.GetEntryPoints();
Defensive patterns

Strategy: validation

Validate before calling

static bool LooksLikeSpirv(ReadOnlySpan<uint> words) =>
    words.Length >= 5 && words[0] == 0x07230203u; // magic number

Type guard

if (!LooksLikeSpirv(words))
    throw new InvalidDataException("Buffer is not a SPIR-V module (bad magic number)");

Try / catch

try { var eps = translator.GetEntryPoints(); }
catch (Exception ex) when (ex.Message.Contains("Could not parse spirv")) {
    InvalidateShaderCache(blobId); // discard corrupt/unsupported module
}

Prevention

When it happens

Trigger: Calling GetEntryPoints on a SpirvTranslator whose Words.Span does not contain valid SPIR-V: buffer written in wrong endianness/offset, HLSL/DXBC or DXIL bytes passed instead of SPIR-V, truncated buffer, or SPIR-V version newer than the bundled parser.

Common situations: Feeding translated-then-saved shader blobs from an incompatible backend; cache corruption; passing a shader bytecode buffer produced for a different API (e.g. DXBC) into the SPIR-V translator.

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


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/b2bd1a249ac9c652. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Compilers/SpirvTranslator.cs:35

    static readonly Cross cross;
    static readonly Logger Log = GlobalLogger.GetLogger("SpirvTranslator");

    static SpirvTranslator()
    {
        NativeLibraryHelper.PreloadLibrary("spirv-cross", typeof(SpirvTranslator));
        cross = Cross.GetApi();
    }

    public List<(string RealName, string TranslatedName, ExecutionModel ExecutionModel)> GetEntryPoints(Backend backend = Backend.Hlsl)
    {
        Context* context = null;
        ParsedIr* ir = null;
        Compiler* compiler = null;
        if (cross.ContextCreate(&context) != Result.Success)
            throw new Exception($"{cross.ContextCreate(&context)} : Could not create spirv context");
        fixed (uint* w = Words.Span)
            if (cross.ContextParseSpirv(context, w, (nuint)Words.Length, &ir) != Result.Success)
                throw new Exception($"{cross.ContextParseSpirv(context, w, (nuint)Words.Length, &ir)} : Could not parse spirv");

        cross.ContextSetErrorCallback(context, new((void* userData, byte* errorData) =>
        {
            var error = Marshal.PtrToStringAnsi((IntPtr)errorData);
            if (error != null)
                Log.Error(error);
        }), null);

        if (cross.ContextCreateCompiler(context, backend, ir, CaptureMode.Copy, &compiler) != Result.Success)
            throw new Exception($"{cross.ContextCreateCompiler(context, backend, ir, CaptureMode.Copy, &compiler)} : could not create compiler");

        var result = new List<(string RealName, string TranslatedName, ExecutionModel ExecutionModel)>();
        EntryPoint* entry_points = null;
        nuint num_entry_points = 0;
        cross.CompilerGetEntryPoints(compiler, &entry_points, &num_entry_points);
        for (int i = 0; i < (int)num_entry_points; ++i)
        {
            var entryPointModel = entry_points[i].ExecutionModel;

View on GitHub (pinned to 96fad776d2)