{"record":{"id":"7b2fed13c7b0cfa2","repo":"stride3d/stride","slug":"two-variables-with-same-semantic-stream-value-semantic-have","errorCode":null,"errorMessage":"Two variables with same semantic {stream.Value.Semantic} have different types {stream.Value.Type} and {firstStream.Value.Type}","messagePattern":"Two variables with same semantic (.+?) have different types (.+?) and (.+?)","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Cleanup/VariableMerger.cs","lineNumber":29,"sourceCode":"/// <summary>\n/// Handles merging of variables with the same semantic and propagating streams between shader stages.\n/// </summary>\ninternal static class VariableMerger\n{\n    /// <summary>\n    /// Merges variables that have the same semantic into a single variable.\n    /// </summary>\n    public static void MergeSameSemanticVariables(SymbolTable table, SpirvContext context, SpirvBuffer buffer, AnalysisResult analysisResult)\n    {\n        Dictionary<int, int> remapIds = new();\n        foreach (var streamWithSameSemantic in analysisResult.Streams.Where(x => x.Value.Semantic != null).GroupBy(x => x.Value.Semantic))\n        {\n            // Make sure they all have the same type\n            var firstStream = streamWithSameSemantic.First();\n            foreach (var stream in streamWithSameSemantic.Skip(1))\n            {\n                if (stream.Value.Type != firstStream.Value.Type)\n                    throw new InvalidOperationException($\"Two variables with same semantic {stream.Value.Semantic} have different types {stream.Value.Type} and {firstStream.Value.Type}\");\n\n                // Remap variable\n                remapIds.Add(stream.Key, firstStream.Key);\n            }\n        }\n\n        // Remove duplicate streams\n        HashSet<int> removedIds = new();\n        foreach (var i in buffer)\n        {\n            if (i.Op == Op.OpVariableSDSL && ((OpVariableSDSL)i) is { } variable && remapIds.ContainsKey(variable.ResultId))\n            {\n                SpirvBuilder.SetOpNop(i.Data.Memory.Span);\n                removedIds.Add(variable.ResultId);\n            }\n        }\n\n        // Remove OpName/OpDecorate","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Cleanup/VariableMerger.cs#L11-L47","documentation":"VariableMerger.MergeSameSemanticVariables merges interface variables that share the same semantic (e.g. TEXCOORD0). Merging is only valid if all variables with that semantic have identical types; if a later variable's Type differs from the first, merging would corrupt the interface layout, so it throws InvalidOperationException.","triggerScenarios":"Two or more variables decorated with the same semantic but declared with different types (e.g. float2 TEXCOORD0 in one stage, float4 TEXCOORD0 in another) reaching MergeSameSemanticVariables.","commonSituations":"Vertex/pixel shader signature mismatch for the same semantic; a composed shader (mixin/inheritance) where different stages declare the same semantic with different widths; library shaders and user shaders disagreeing on a semantic's type.","solutions":["Make all declarations of the same semantic use the identical type across stages","Rename one of the conflicting semantics (e.g. TEXCOORD1) if the data differs","Check composed shader/mixin signatures for a drifted semantic type and align it","If the difference is intentional (widening), perform an explicit cast/intermediate variable instead of relying on merging"],"exampleFix":"// before\n// vertex: float2 TexCoord : TEXCOORD0;\n// pixel:  float4 TexCoord : TEXCOORD0;\n// after\n// both stages: float4 TexCoord : TEXCOORD0; (or use separate semantics)","handlingStrategy":"validation","validationCode":"var bySemantic = variables.GroupBy(v => v.Semantic);\nforeach (var g in bySemantic)\n    if (g.Select(v => v.Type).Distinct().Count() > 1)\n        throw new InvalidOperationException($\"Semantic {g.Key} declared with multiple types: {string.Join(\", \", g.Select(v => v.Type))}\");","typeGuard":null,"tryCatchPattern":"try { merger.MergeSameSemanticVariables(module); } catch (InvalidOperationException ex) { logger.LogError(ex, \"Semantic type conflict across stages\"); throw; }","preventionTips":["Keep semantic declarations identical across vertex/geometry/pixel stages","Align mixin/inheritance shader signatures for shared semantics","Use distinct semantics for differently-typed data","Add cross-stage signature validation before merging"],"tags":["shader","interface","semantic"],"backgroundTag":"type-mismatch","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}