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

  1. Change the dependency property's type to a supported shader constant type (use float, not double, for scalar values).
  2. Convert unsupported types manually: keep the DP as-is but pass a float[] via a separate supported DP, or precompute into float properties.
  3. For brush inputs use PixelShaderSamplerCallback, not PixelShaderConstantCallback.
  4. 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

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


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)