{"record":{"id":"466100ed8c9f4fa0","repo":"stride3d/stride","slug":"can-t-cast-from-v1-to-v2-more-components","errorCode":null,"errorMessage":"Can't cast from {v1} to {v2} (more components)","messagePattern":"Can't cast from (.+?) to (.+?) \\(more components\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs","lineNumber":556,"sourceCode":"                values[0] = valueId;\n                break;\n            case (ScalarType s1, VectorType v2):\n                values[0] = valueId;\n                break;\n            case (ScalarType s1, MatrixType m2):\n                values[0] = valueId;\n                break;\n            case (VectorType v1, ScalarType s2):\n                {\n                    values[0] = Insert(new OpCompositeExtract(context.GetOrRegister(v1.BaseType), context.Bound++, valueId, [0])).ResultId;\n                    valueType = v1.BaseType;\n                    break;\n                }\n            case (VectorType v1, VectorType v2) when v1.Size == v2.Size:\n                values[0] = valueId;\n                break;\n            case (VectorType v1, VectorType v2) when v1.Size < v2.Size:\n                throw new InvalidOperationException($\"Can't cast from {v1} to {v2} (more components)\");\n            case (VectorType v1, VectorType v2) when v1.Size > v2.Size:\n                {\n                    Span<int> valuesTemp = stackalloc int[v2.Size];\n                    for (int i = 0; i < v2.Size; ++i)\n                        Insert(new OpCompositeExtract(context.GetOrRegister(v1.BaseType), valuesTemp[i] = context.Bound++, valueId, [i]));\n                    valueType = new VectorType(v1.BaseType, v2.Size);\n                    values[0] = Insert(new OpCompositeConstruct(context.GetOrRegister(valueType), context.Bound++, new LiteralArray<int>(valuesTemp))).ResultId;\n                    break;\n                }\n            case (VectorType v1, MatrixType m2) when v1.Size != m2.Rows * m2.Columns:\n                throw new InvalidOperationException($\"Can't cast from {v1} to {m2}\");\n            case (VectorType v1, MatrixType m2) when v1.Size == m2.Rows * m2.Columns:\n                throw new NotImplementedException($\"Cast from {v1} to {m2} is not implemented (even though it should be valid since number of components is same\");\n            case (MatrixType m1, ScalarType s2):\n                values[0] = Insert(new OpCompositeExtract(context.GetOrRegister(m1.BaseType), context.Bound++, valueId, [0, 0])).ResultId;\n                break;\n            case (MatrixType m1, VectorType v2) when v2.Size != m1.Rows * m1.Columns:\n                throw new InvalidOperationException($\"Can't cast from {m1} to {v2}\");","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs#L538-L574","documentation":"In Convert's vector-to-vector conversion, growing a vector (source has fewer components than target) is not implemented: SPIR-V vector casts are handled by truncation (extracting leading components), not by extension with default values. A cast from a smaller vector to a larger one therefore throws InvalidOperationException.","triggerScenarios":"Casting e.g. float2 to float4 through Convert — v1.Size < v2.Size triggers the throw (float4→float2 truncation is fine).","commonSituations":"Assigning a short vector (or texcoord/offset value) to a longer vector type; ConvertTexCoord/ConvertOffset receiving fewer components than the sampling API requires; implicit conversions attempted by overload resolution.","solutions":["Explicitly pad the smaller vector (e.g. float4(v.xy, 0, 1)) before conversion","Truncate the larger side instead: change the target to the source's size","Construct the target vector component-wise from the source components plus explicit fill values","Update the calling helper (e.g. ConvertTexCoord) to accept the actual component count"],"exampleFix":"// before\nfloat4 p = (float4)texcoord2; // float2 -> float4 not allowed\n// after\nfloat4 p = float4(texcoord2, 0.0f, 1.0f); // explicit pad","handlingStrategy":"type-guard","validationCode":"if (valueType is VectorType v1 && castType is VectorType v2 && v1.Size < v2.Size)\n    throw new InvalidOperationException($\"Cannot grow vector {v1} to {v2}; pad explicitly\");","typeGuard":"bool VectorSizeOk(VectorType src, VectorType dst) => src.Size >= dst.Size;","tryCatchPattern":"try { converted = Builder.Convert(value, castType); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"more components\"))\n{ /* pad the source vector explicitly before converting */ }","preventionTips":["Pad short vectors explicitly (float4(v, 0, 1)) rather than casting up","Keep texcoord/offset vector widths consistent with sampling APIs","Prefer truncation (larger→smaller) which Convert supports"],"tags":["spirv","shader-compiler","vector","casting"],"backgroundTag":"shape-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"}