stride3d/stride · error · NotSupportedException

BorderColor must be float4(r, g, b, a)

Error message

BorderColor must be float4(r, g, b, a)

What it means

When compiling a SamplerState declaration, the BorderColor parameter must be a float4 literal with exactly 4 numeric components. The compiler packs all four RGBA values into integers for the SPIR-V immutable sampler; anything else (wrong type, wrong type name, wrong arity) is rejected with this NotSupportedException.

Solutions

  1. Change the BorderColor argument to a float4 literal with exactly 4 components, e.g. BorderColor(float4(0, 0, 0, 1)).
  2. Verify the literal is parsed as a VectorLiteral with TypeName 'float4'; ensure the constructor call spells the type float4.
  3. If a non-float4 border color is needed, set sampler state at runtime via Parameters.Set() instead of an inline declaration.

Example fix

// before
sampler2D Tex : BorderColor(0);
// after
sampler2D Tex : BorderColor(float4(0, 0, 0, 1));
Defensive patterns

Strategy: validation

Validate before calling

if (param.Value is not VectorLiteral { TypeName.Name: "float4", Values: { Count: 4 } })
    throw new ArgumentException("BorderColor must be float4(r, g, b, a)");

Type guard

static bool IsValidBorderColor(object v) =>
    v is VectorLiteral vl && vl.TypeName.Name == "float4" && vl.Values.Count == 4;

Try / catch

try { sampler.Compile(); }
catch (NotSupportedException ex) when (ex.Message.Contains("BorderColor must be float4"))
{
    // rewrite the BorderColor parameter as float4(r, g, b, a) and retry
}

Prevention

When it happens

Trigger: A shader declares a sampler with an inline BorderColor parameter whose value is not a VectorLiteral typed 'float4' with exactly 4 values, e.g. BorderColor(0) or BorderColor(float3(...)).

Common situations: Porting HLSL sampler state from FX files, hand-editing a sampler and dropping a component, or using a variable/expression instead of a literal.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/ff90155fa94eefe9. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/ShaderElements.MethodOrMember.cs:107

                case "MipLODBias":
                    mipLODBias = BitConverter.SingleToInt32Bits((float)((FloatLiteral)parameter.Value).Value);
                    break;
                case "MaxAnisotropy":
                    maxAnisotropy = ((IntegerLiteral)parameter.Value).IntValue;
                    break;
                case "ComparisonFunc":
                    comparisonFunc = (int)Enum.Parse<Specification.SamplerComparisonFuncSDSL>(((Identifier)parameter.Value).Name, true);
                    break;
                case "MinLOD":
                    minLOD = BitConverter.SingleToInt32Bits((float)((FloatLiteral)parameter.Value).Value);
                    break;
                case "MaxLOD":
                    maxLOD = BitConverter.SingleToInt32Bits((float)((FloatLiteral)parameter.Value).Value);
                    break;
                case "BorderColor":
                    {
                        if (parameter.Value is not VectorLiteral { TypeName.Name: "float4", Values: { Count: 4 } args })
                            throw new NotSupportedException($"BorderColor must be float4(r, g, b, a)");
                        borderR = BitConverter.SingleToInt32Bits((float)((NumberLiteral)args[0]).DoubleValue);
                        borderG = BitConverter.SingleToInt32Bits((float)((NumberLiteral)args[1]).DoubleValue);
                        borderB = BitConverter.SingleToInt32Bits((float)((NumberLiteral)args[2]).DoubleValue);
                        borderA = BitConverter.SingleToInt32Bits((float)((NumberLiteral)args[3]).DoubleValue);
                        break;
                    }
                default:
                    throw new NotImplementedException($"SamplerState parameter '{parameter.Name}' not implemented");
            }
        }
        // Only emit immutable sampler state when the declaration has explicit parameters.
        // Samplers without inline state (e.g. "stage SamplerState Sampler;") are dynamic
        // and set at runtime via Parameters.Set().
        if (Parameters.Count > 0)
        {
            context.Add(new OpDecorate(variableId, Specification.Decoration.SamplerStateSDSL, [
                filter, addressU, addressV, addressW, mipLODBias, maxAnisotropy, comparisonFunc, minLOD, maxLOD,
                borderR, borderG, borderB, borderA

View on GitHub (pinned to 96fad776d2)