stride3d/stride · error · NotImplementedException

Type conversion from

Error message

Type conversion from {originalType} to {castType} failed after expansion (current type: {valueType})

What it means

Final sanity check of Builder.Expressions.Convert: after all expansion and element-wise cast steps, if the resulting valueType still differs from the requested castType, the conversion pipeline failed and a NotImplementedException is thrown. It means no case in the big type-pair switch handled this (originalType, castType) combination.

Solutions

  1. Simplify or split the cast in the shader so each step is a supported combination.
  2. Add the missing case in Builder.Expressions.cs to expand/retype to castType.
  3. Search/upgrade Stride for the specific cast combination support.

Example fix

// before (shader)
uint3x3 m = (uint3x3)float3x3f;
// after
uint3 r0 = (uint3)f[0]; uint3 r1 = (uint3)f[1]; uint3 r2 = (uint3)f[2];
Defensive patterns

Strategy: try-catch

Validate before calling

bool sameShape(SymbolType a, SymbolType b) => a.GetType() == b.GetType(); // plus element/size equality

Type guard

bool ConvertWillFail(SymbolType original, SymbolType target) => original is MatrixType mo && target is MatrixType mt && (mo.Rows != mt.Rows || mo.Columns != mt.Columns);

Try / catch

try { result = builder.Convert(table, context, value, castType); }
catch (NotImplementedException e) when (e.Message.Contains("failed after expansion"))
{ Log.Error($"Unsupported cast {value} -> {castType}"); throw; }

Prevention

When it happens

Trigger: Calling Convert with a type combination for which none of the expansion cases (scalar/vector/matrix) produce exactly castType — e.g. an unhandled matrix-to-different-matrix element retype or a vector with an unhandled element cast.

Common situations: Unusual casts in shader code (mixed element-size changes on composites) or a Stride version lacking support for the combination; surfaces during shader compilation (ConvertTexCoord, CompileSign, etc.).

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:684

        {
            case (ScalarType, VectorType v2):
                result = Insert(new OpCompositeConstruct(context.GetOrRegister(v2), context.Bound++, new LiteralArray<int>(Enumerable.Repeat(result, v2.Size).ToArray())));
                valueType = v2;
                break;
            case (ScalarType, MatrixType m2):
                result = Insert(new OpCompositeConstruct(context.GetOrRegister(new VectorType(m2.BaseType, m2.Rows)), context.Bound++, new LiteralArray<int>(Enumerable.Repeat(result, m2.Rows).ToArray())));
                result = Insert(new OpCompositeConstruct(context.GetOrRegister(m2), context.Bound++, new LiteralArray<int>(Enumerable.Repeat(result, m2.Columns).ToArray())));
                valueType = m2;
                break;
            case (VectorType, MatrixType m2):
                // rebuild type
                result = Insert(new OpCompositeConstruct(context.GetOrRegister(m2), context.Bound++, new LiteralArray<int>(values)));
                valueType = m2;
                break;
        }

        if (valueType != castType)
            throw new NotImplementedException($"Type conversion from {originalType} to {castType} failed after expansion (current type: {valueType})");

        return new SpirvValue(result, context.GetOrRegister(castType));
    }

    public SpirvValue CallFunction(SymbolTable table, SpirvContext context, Symbol functionSymbol, Span<int> parameters)
    {
        // Note: Overload should have been chosen before
        if (functionSymbol.Type is FunctionGroupType)
            throw new InvalidOperationException();

        var functionType = (FunctionType)functionSymbol.Type;
        var fcall = Buffer.InsertData(Position++, new OpFunctionCall(context.GetOrRegister(functionType.ReturnType), context.Bound++, functionSymbol.IdRef, [.. parameters]));
        return new(fcall, functionSymbol.Id.Name);
    }
}


View on GitHub (pinned to 96fad776d2)