dotnet/wpf · error · ArgumentException

SR.GetResourceString(srid)

Error message

SR.GetResourceString(srid)

What it means

In UpdateShaderConstant, after determining the register limits for the shader profile (e.g. PS_2_0 vs PS_3_0 constant register maxima, with the srid selecting the matching message such as Effect_Shader30BoolConstantRegisterLimit), a register index outside [0, registerMax) makes the effect throw ArgumentException with the corresponding resource string. The register referenced by PixelShaderConstantCallback does not exist in the shader profile.

Solutions

  1. Use a register index within the profile limit, or compile the shader with /T ps_3_0 to raise the limits.
  2. Reduce the number of constants (pack values into float4 registers, use arrays) to fit within the limit.
  3. Fix the register index passed to PixelShaderConstantCallback (must be >= 0 and < registerMax).

Example fix

// before
new PropertyMetadata(0f, PixelShaderConstantCallback(45))); // ps_2_0 float limit exceeded
// after
new PropertyMetadata(0f, PixelShaderConstantCallback(12))); // within ps_2_0 limit
Defensive patterns

Strategy: validation

Validate before calling

// ps_2_0 float register limit is 32; check before registering the callback
if (registerIndex < 0 || registerIndex >= 32)
    throw new ArgumentException("Constant register index out of range for the shader profile");

Try / catch

try
{
    effect.ApplyAnimationClock(dp, null); // triggers UpdateShaderConstant path
}
catch (ArgumentException ex) when (ex.Message.Contains("register"))
{
    // remap register index or recompile shader as ps_3_0
}

Prevention

When it happens

Trigger: Passing a register number >= the profile limit (e.g. register 32+ for float constants in ps_2_0, or bool/int registers with ps_2_0) or a negative register index to PixelShaderConstantCallback.

Common situations: Adding many shader parameters and running past the ps_2_0 constant register cap; reusing callback register numbers copied from ps_3_0 samples while the shader is compiled ps_2_0; typo in the register index (off-by-one or negative).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/5a118a23d543d863. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Effects/ShaderEffect.cs:372

                    {
                        registerMax = PS_3_0_FLOAT_REGISTER_LIMIT;
                        srid = nameof(SR.Effect_Shader30FloatConstantRegisterLimit);
                    }
                    else if (t == typeof(int))
                    {
                        registerMax = PS_3_0_INT_REGISTER_LIMIT;
                        srid = nameof(SR.Effect_Shader30IntConstantRegisterLimit);
                    }
                    else if (t == typeof(bool))
                    {
                        registerMax = PS_3_0_BOOL_REGISTER_LIMIT;
                        srid = nameof(SR.Effect_Shader30BoolConstantRegisterLimit);
                    }
                }

                if (registerIndex >= registerMax || registerIndex < 0)
                {
                    throw new ArgumentException(SR.GetResourceString(srid), nameof(dp));
                }

                if (t == typeof(float))
                {
                    MilColorF fourTuple;
                    ConvertValueToMilColorF(newValue, out fourTuple);
                    StashInPosition(ref _floatRegisters, registerIndex, fourTuple, registerMax, ref _floatCount);
                }
                else if (t == typeof(int))
                {
                    MilColorI fourTuple;
                    ConvertValueToMilColorI(newValue, out fourTuple);
                    StashInPosition(ref _intRegisters, registerIndex, fourTuple, registerMax, ref _intCount);
                }
                else if (t == typeof(bool))
                {
                    StashInPosition(ref _boolRegisters, registerIndex, (bool)newValue, registerMax, ref _boolCount);
                }

View on GitHub (pinned to 81131a70a4)