stride3d/stride · error · NotSupportedException
Unsupported symbol type: {symbolType}
Error message
Unsupported symbol type: {symbolType} What it means
ConvertType maps SDSL parser type symbols (base types, vectors, matrices, scalars) to effect reflection types (EffectParameterType/Class). The switch covers the known set of TypeBase-derived symbols; any other symbolType reaching it has no reflection representation and triggers this NotSupportedException. It is an exhaustiveness guard so new/unknown SDSL type symbols fail loudly instead of producing wrong reflection data.
Solutions
- Look at the symbolType value in the message to identify the unhandled type kind.
- Add a matching case in the ConvertType switch to translate that symbol type into the correct EffectParameterType/Class.
- If the type shouldn't appear here (e.g. textures/samplers in a cbuffer), fix the earlier parsing/collecting stage so those symbols are excluded before ComputeCBufferReflection.
- Update or align your Stride version: if the type is new, ensure the reflection converter from the matching version is used.
Example fix
// before
_ => throw new NotSupportedException($"Unsupported symbol type: {symbolType}"),
// after
SamplerType s => new EffectParameterTypeDescription { Class = EffectParameterClass.Object, Type = EffectParameterType.Sampler },
_ => throw new NotSupportedException($"Unsupported symbol type: {symbolType}"), Defensive patterns
Strategy: validation
Validate before calling
// Check the symbol type is one ConvertType handles before reflection conversion
var supported = symbolType is BaseType or VectorType or MatrixType or ScalarType;
if (!supported) throw new InvalidOperationException($"Type {symbolType} cannot be converted to effect reflection data."); Type guard
bool IsReflectableType(TypeBase t) => t is BaseType or VectorType or MatrixType or ScalarType;
Try / catch
try { var desc = ConvertType(context, symbolType, typeModifier, alignmentRules); }
catch (NotSupportedException ex) { log.Error($"Reflection conversion failed: {ex.Message}. Ensure only scalars/vectors/matrices reach ConvertType."); throw; } Prevention
- Filter out non-value types (samplers, textures, structs, pointers) before cbuffer reflection conversion.
- Update ConvertType's switch whenever the SDSL parser adds new type kinds.
- Cover all TypeBase derived types in unit tests for ConvertType.
When it happens
Trigger: ConvertType is called (directly, or via ConvertStructType, element-type conversion, or ComputeCBufferReflection) with a symbolType outside the mapped set — e.g. a struct/pointer/sampler/user-defined type symbol or a newly added SDSL type kind that the converter has no case for.
Common situations: A newly introduced SDSL language type not yet handled in ConvertType; a type declaration reaching cbuffer reflection that should have been filtered out earlier (e.g. samplers or textures inside a cbuffer declaration); custom parser extensions producing unknown symbol types.
Related errors
- {this} could not resolve symbol
- Could not resolve type [{Name}]
- Unsupported StreamsKindSDSL for output parameter: {t.Kind}
- The associated asset type does not have a public parameterle
- The given instance is a value type and cannot have a item id
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/d6113d6a5635d6cd.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.CBuffers.cs:420
{
return symbolType switch
{
ScalarType { Type: Scalar.Boolean } => new EffectTypeDescription { Class = EffectParameterClass.Scalar, Type = EffectParameterType.Bool, RowCount = 1, ColumnCount = 1, ElementSize = 4 },
ScalarType { Type: Scalar.UInt } => new EffectTypeDescription { Class = EffectParameterClass.Scalar, Type = EffectParameterType.UInt, RowCount = 1, ColumnCount = 1, ElementSize = 4 },
ScalarType { Type: Scalar.Int } => new EffectTypeDescription { Class = EffectParameterClass.Scalar, Type = EffectParameterType.Int, RowCount = 1, ColumnCount = 1, ElementSize = 4 },
ScalarType { Type: Scalar.Float } => new EffectTypeDescription { Class = EffectParameterClass.Scalar, Type = EffectParameterType.Float, RowCount = 1, ColumnCount = 1, ElementSize = 4 },
ScalarType { Type: Scalar.Double } => new EffectTypeDescription { Class = EffectParameterClass.Scalar, Type = EffectParameterType.Double, RowCount = 1, ColumnCount = 1, ElementSize = 8 },
ArrayType a => ConvertArrayType(context, a, typeModifier, alignmentRules),
StructType s => ConvertStructType(context, s, alignmentRules),
// TODO: should we use RowCount instead? (need to update Stride)
VectorType v => ConvertType(context, v.BaseType, typeModifier, alignmentRules) with { Class = EffectParameterClass.Vector, RowCount = 1, ColumnCount = v.Size },
// Note: this is HLSL-style so Rows/Columns meaning is swapped
// however, for type/class, both TypeModifier and EffectParameterType are following HLSL
MatrixType m when typeModifier == TypeModifier.ColumnMajor || typeModifier == TypeModifier.None
=> ConvertType(context, m.BaseType, typeModifier, alignmentRules) with { Class = EffectParameterClass.MatrixColumns, RowCount = m.Columns, ColumnCount = m.Rows },
MatrixType m when typeModifier == TypeModifier.RowMajor
=> ConvertType(context, m.BaseType, typeModifier, alignmentRules) with { Class = EffectParameterClass.MatrixRows, RowCount = m.Columns, ColumnCount = m.Rows },
_ => throw new NotSupportedException($"Unsupported symbol type: {symbolType}"),
};
}
private void ComputeCBufferReflection(MixinGlobalContext globalContext, SpirvContext context, SpirvBuffer buffer)
{
var cbuffers = buffer
.Where(x => x.Op == Op.OpVariableSDSL)
// Note: MemberIndexOffset is simply a shift in Members index, not something like a byte offset
.Select(x => (
Variable: x,
VariableId: x.Data.IdResult!.Value,
StructTypePtrId: x.Data.IdResultType!.Value,
StructType: context.ReverseTypes[x.Data.IdResultType.Value] is PointerType p && p.StorageClass == Specification.StorageClass.Uniform && p.BaseType is StructuredType s ? s : null,
MemberIndexOffset: 0))
.Where(x => x.StructType != null)
.ToList();
foreach (var cbuffer in cbuffers)View on GitHub (pinned to 96fad776d2)