{"record":{"id":"afff4a14dd602656","repo":"stride3d/stride","slug":"can-t-convert-interface-variable-from-sourcetype-to-casttype","errorCode":null,"errorMessage":"Can't convert interface variable from {sourceType} to {castType}","messagePattern":"Can't convert interface variable from (.+?) to (.+?)","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Generation/BuiltinProcessor.cs","lineNumber":54,"sourceCode":"    /// <summary>\n    /// Converts interface variables between types, handling vector and array size mismatches.\n    /// Used when builtin types have different sizes than shader types.\n    /// </summary>\n    public static int ConvertInterfaceVariable(\n        SpirvBuffer buffer,\n        SpirvContext context,\n        SymbolType sourceType,\n        SymbolType castType,\n        int value)\n    {\n        if (sourceType == castType)\n            return value;\n\n        var (castSize, castBaseType) = ExtractSizeAndBaseType(castType);\n        var (sourceSize, sourceBaseType) = ExtractSizeAndBaseType(sourceType);\n\n        if (castBaseType != sourceBaseType)\n            throw new InvalidOperationException($\"Can't convert interface variable from {sourceType} to {castType}\");\n\n        Span<int> components = stackalloc int[castSize];\n\n        for (int i = 0; i < castSize; ++i)\n        {\n            components[i] = i < sourceSize\n                ? (sourceType is ScalarType ? value : buffer.Add(new OpCompositeExtract(context.GetOrRegister(sourceBaseType), context.Bound++, value, [i])).ResultId)\n                : context.CreateDefaultConstantComposite(sourceBaseType).Id;\n        }\n\n        return castType is ScalarType\n            ? components[0]\n            : buffer.Add(new OpCompositeConstruct(context.GetOrRegister(castType), context.Bound++, new(components))).ResultId;\n\n        (int Size, SymbolType baseType) ExtractSizeAndBaseType(SymbolType castType)\n        {\n            return castType switch\n            {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Generation/BuiltinProcessor.cs#L36-L72","documentation":"BuiltinProcessor.ConvertInterfaceVariable converts an interface variable's value to a cast type by resizing component vectors. Conversion is only allowed when base scalar types match; if castBaseType != sourceBaseType (e.g. float vs int semantic variable) the conversion is undefined and it throws InvalidOperationException.","triggerScenarios":"Applying a semantic/builtin cast where the target and source differ in base scalar type — e.g. a float4 semantic read and reinterpreted as an int4 (SV_Position to integer), or uint vs float builtin remaps.","commonSituations":"Shader code assigning a builtin/system-value to a variable of a different scalar type; remapping tables mapping SV_* semantics to differently typed variables; accidental int/float mixup in an interface struct.","solutions":["Match the base scalar type of the variable to the semantic's expected type (float for most SV_* positions, uint for sample masks, etc.)","Insert an explicit conversion in the shader body (e.g. (int4)streams.Position) instead of relying on interface-variable conversion","Check the builtin remapping table entry that produced the incompatible castType","If conversion should be supported, extend ConvertInterfaceVariable to emit a numeric conversion instead of throwing"],"exampleFix":"// before\nint4 pos : SV_Position; // int vs float builtin\n// after\nfloat4 pos : SV_Position; // convert explicitly in body if int needed: var p = (int4)streams.Position;","handlingStrategy":"type-guard","validationCode":"var (_, castBase) = ExtractSizeAndBaseType(castType);\nvar (_, srcBase)  = ExtractSizeAndBaseType(sourceType);\nif (castBase != srcBase) throw new InvalidOperationException($\"Interface cast requires matching base types: {srcBase} vs {castBase}\");","typeGuard":"bool IsConvertibleCast(SdslType source, SdslType cast) => ExtractSizeAndBaseType(source).BaseType == ExtractSizeAndBaseType(cast).BaseType;","tryCatchPattern":"try { var v = processor.ConvertInterfaceVariable(value, castType); } catch (InvalidOperationException ex) { logger.LogError(ex, \"Builtin type conversion rejected\"); throw; }","preventionTips":["Type semantic variables to match their system-value semantics (float4 for SV_Position, etc.)","Avoid int/float mixing between builtin tables and interface structs","Insert explicit conversions in shader body instead of interface-level casts"],"tags":["shader","interface","type-conversion"],"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"}