stride3d/stride · error · InvalidOperationException
Semantic requested with type but last time with
Error message
Semantic {semantic} requested with type {type} but last time with {result.Type} What it means
EntryPointWrapperGenerator caches declared builtin variables by semantic name. If the same semantic is requested a second time with a different SymbolType than the first declaration, it throws InvalidOperationException because SPIR-V requires one consistent type per builtin variable; silently reusing it with a different type would produce invalid SPIR-V.
Solutions
- Make all uses of the same semantic use one identical SymbolType (match component count and base type) in the entry-point signature.
- If different types are truly needed, use distinct semantic names so each gets its own builtin variable.
- Inspect GetOrDeclareBuiltInValue calls in EntryPointWrapperGenerator.cs:67 to see the conflicting types reported in the message and align the offending declaration.
- Recheck upstream SDSL/HLSL struct definitions for the stream layout so types agree before wrapper generation.
Example fix
// before void CSMain(uint3 id : SV_GroupID, uint3 threadId : SV_GroupThreadID, float3 extra : SV_GroupID) // SV_GroupID as float3 conflicts with uint3 // after void CSMain(uint3 id : SV_GroupID, uint3 threadId : SV_GroupThreadID) // single consistent uint3 declaration per semantic
Defensive patterns
Strategy: validation
Validate before calling
// Ensure every semantic is declared with exactly one type across the entry-point signature var bySemantic = parameters.GroupBy(p => p.Semantic, StringComparer.OrdinalIgnoreCase); bool typesConsistent = bySemantic.All(g => g.Select(p => p.Type).Distinct().Count() == 1);
Type guard
static bool HasConsistentSemanticTypes(IEnumerable<(string Semantic, SymbolType Type)> decls) =>
decls.GroupBy(d => d.Semantic, StringComparer.OrdinalIgnoreCase)
.All(g => g.Select(d => d.Type).Distinct().Count() <= 1); Try / catch
try
{
var id = GetOrDeclareBuiltInValue(type, semantic);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("requested with type"))
{
log.Error($"Conflicting types for semantic '{semantic}': {ex.Message}");
throw new ShaderCompilationException($"Semantic '{semantic}' declared with conflicting types in entry point", ex);
} Prevention
- Declare each system-value semantic once and reuse the variable instead of redeclaring it with different types.
- Enforce in the SDSL/HLSL front-end that a semantic maps to exactly one SymbolType per entry point.
- Match vector component counts exactly (e.g. float4 vs float3 mismatches are the usual culprit).
- Add a signature-validation test that groups parameters by semantic and asserts type uniqueness.
When it happens
Trigger: GenerateWrapper processes two parameters (or two stream members) carrying the same semantic string, but their resolved SymbolTypes differ, e.g. the same SV_ semantic declared as float4 in one place and float3 (or uint) in another within a single entry-point wrapper.
Common situations: HLSL/SDSL signatures where the same system value appears on both an entry-point parameter and a struct member with mismatched vector/component types; recent refactors that changed one declaration's type but not the other; copy-paste of parameters where one lost a swizzle-compatible type.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Second parameter of geometry shader must be a…
- spirv_to_dxil_pipeline failed; SPIR-V dumped to
- Can't OpLoad with cbuffer
- Unsupported type for non-pointer indexer
- Unsupported element type for clamp
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/4fbbececa162dfd1.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Generation/EntryPointWrapperGenerator.cs:67
var variableValueType = variable.Value.Type.BaseType;
var methodInitializerCall = buffer.Add(new OpFunctionCall(context.GetOrRegister(variableValueType), context.Bound++, methodInitializerId, []));
buffer.Add(new OpStore(variable.Value.VariableId, methodInitializerCall.ResultId, null, []));
}
}
// Update entry point type (since Streams type might have been replaced)
entryPointFunctionType = (FunctionType)entryPoint.Type;
var builtinVariables = new Dictionary<string, (SymbolType Type, int Id)>();
var entryPointExtraVariables = new List<int>();
int GetOrDeclareBuiltInValue(SymbolType type, string semantic)
{
semantic = semantic.ToUpperInvariant();
if (builtinVariables.TryGetValue(semantic, out var result))
{
if (result.Type != type)
throw new InvalidOperationException($"Semantic {semantic} requested with type {type} but last time with {result.Type}");
return result.Id;
}
// Declare the global builtin
var variableId = context.Bound++;
if (!BuiltinProcessor.ProcessBuiltinsDecoration(context, executionModel, variableId, StreamVariableType.Input, semantic, ref type))
throw new InvalidOperationException();
var variable = context.Add(new OpVariable(context.GetOrRegister(new PointerType(type, Specification.StorageClass.Input)), variableId, Specification.StorageClass.Input, null)).ResultId;
entryPointExtraVariables.Add(variable);
var value = buffer.Add(new OpLoad(context.GetOrRegister(type), context.Bound++, variable, null, [])).ResultId;
builtinVariables.Add(semantic, (type, value));
return value;
}
void FillSemanticArguments(FunctionType functionType, Span<int> arguments)
{
foreach (var i in context)
{View on GitHub (pinned to 96fad776d2)