dotnet/wpf · error · InvalidOperationException
SR.Effect_ShaderConstantType
Error message
SR.Effect_ShaderConstantType
What it means
UpdateShaderConstant calls DetermineShaderConstantType to map a dependency property's CLR type onto a shader constant register type (float/int/bool/sampler). If the property type is not one of the supported shader constant types, InvalidOperationException with Effect_ShaderConstantType (including the type name) is thrown.
Solutions
- Change the dependency property's type to a supported shader constant type (use float, not double, for scalar values).
- Convert unsupported types manually: keep the DP as-is but pass a float[] via a separate supported DP, or precompute into float properties.
- For brush inputs use PixelShaderSamplerCallback, not PixelShaderConstantCallback.
- For int/bool constants ensure the shader is ps_3_0 (see Effect_20ShaderUsing30Registers).
Example fix
// before
public static readonly DependencyProperty StrengthProperty =
DependencyProperty.Register("Strength", typeof(double), typeof(MyEffect),
new PropertyMetadata(0.0, PixelShaderConstantCallback(0)));
// after
public static readonly DependencyProperty StrengthProperty =
DependencyProperty.Register("Strength", typeof(float), typeof(MyEffect),
new PropertyMetadata(0f, PixelShaderConstantCallback(0))); Defensive patterns
Strategy: validation
Validate before calling
static readonly Type[] SupportedShaderTypes = { typeof(float), typeof(int), typeof(bool), typeof(Point), typeof(Point4D), typeof(Point3D), typeof(Vector), typeof(Vector3D), typeof(Size), typeof(Size3D), typeof(Color), typeof(Matrix), typeof(Quaternion) };
if (!SupportedShaderTypes.Contains(propType))
throw new InvalidOperationException($"{propType.Name} is not a supported shader constant type"); Type guard
static bool IsShaderConstantType(Type t) =>
t == typeof(float) || t == typeof(int) || t == typeof(bool) ||
t == typeof(Point) || t == typeof(Point3D) || t == typeof(Point4D) ||
t == typeof(Vector) || t == typeof(Vector3D) || t == typeof(Size) ||
t == typeof(Size3D) || t == typeof(Color) || t == typeof(Matrix) || t == typeof(Quaternion); Prevention
- Use float (not double) for scalar shader constants.
- Use PixelShaderSamplerCallback for Brush-typed properties, never PixelShaderConstantCallback.
- Remember int/bool constants require ps_3_0 shaders.
When it happens
Trigger: Registering a DependencyProperty whose type is not float/Point/Color/Size/Vector/Matrix/Point3D/Vector3D/Point4D/Quaternion/Size3D/Vector3D/int/bool/etc. (e.g. double, string, custom object) with PixelShaderConstantCallback in a ShaderEffect.
Common situations: Declaring a dependency property as double instead of float for a shader parameter; using string or enum-typed properties with PixelShaderConstantCallback; mistyping a brush property as a constant instead of a sampler.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- SR.Format(SR.DefaultValuePropertyTypeMismatch, propertyName)
- SR.InvalidPropertyValue
- ' ' is not a Visual or Visual3D.
- 0x80070057
- Animation_AnimationTimelineTypeMismatch
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9647034aeb7d5d9a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Effects/ShaderEffect.cs:338
new UIPropertyMetadata(Effect.ImplicitInput,
PixelShaderSamplerCallback(samplerRegisterIndex,
samplingMode)));
}
// Updates the shader constant referred to by the DP. Converts to the
// form that the HLSL shaders want, and stores that value, since it will
// be sent on every update.
// We WritePreamble/Postscript here since this method is called by the user with the callback
// created in PixelShaderConstantCallback.
private void UpdateShaderConstant(DependencyProperty dp, object newValue, int registerIndex)
{
WritePreamble();
Type t = DetermineShaderConstantType(dp.PropertyType, PixelShader);
if (t == null)
{
throw new InvalidOperationException(SR.Format(SR.Effect_ShaderConstantType, dp.PropertyType.Name));
}
else
{
//
// Treat as a float constant in ps_2_0 by default
//
int registerMax = PS_2_0_FLOAT_REGISTER_LIMIT;
string srid = nameof(SR.Effect_Shader20ConstantRegisterLimit);
if (PixelShader != null && PixelShader.ShaderMajorVersion >= 3)
{
//
// If there's a ps_3_0 shader, the limit depends on the type
//
if (t == typeof(float))
{
registerMax = PS_3_0_FLOAT_REGISTER_LIMIT;
srid = nameof(SR.Effect_Shader30FloatConstantRegisterLimit);View on GitHub (pinned to 81131a70a4)