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
- Change the BorderColor argument to a float4 literal with exactly 4 components, e.g. BorderColor(float4(0, 0, 0, 1)).
- Verify the literal is parsed as a VectorLiteral with TypeName 'float4'; ensure the constructor call spells the type float4.
- 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
- Always write BorderColor as a float4 literal with exactly four components.
- Lint sampler declarations against the supported inline parameter list before compiling.
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
- SamplerState parameter
- Constant doesn't have a value
- [Color] attribute can only be applied on float3/float4…
- Struct not found in shader
- Could not find compositions for expression
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, borderAView on GitHub (pinned to 96fad776d2)