dotnet/wpf · error · InvalidOperationException

SR.Effect_ShaderPixelShaderSet

Error message

SR.Effect_ShaderPixelShaderSet

What it means

ShaderEffect requires a PixelShader instance to serialize its state to the render thread (DUCE). During resource update on a composition channel, if PixelShader is null the effect cannot be compiled/uploaded, so WPF throws InvalidOperationException with Effect_ShaderPixelShaderSet.

Solutions

  1. Set the PixelShader property in the ShaderEffect subclass constructor before the effect is used (e.g. PixelShader = new PixelShader { UriSource = new PackUri("...ps") };)
  2. If PixelShader is settable, never assign null; re-create or substitute a default shader instead.
  3. Ensure the compiled .ps file is embedded as a Resource in the assembly so the Pack URI resolves and the shader assignment does not fail silently.
  4. Wrap effect registration in validation that checks PixelShader != null before applying the effect to an element.

Example fix

// before
public class MyEffect : ShaderEffect
{
    public MyEffect()
    {
        UpdateShaderValue(InputProperty);
    }
}
// after
public class MyEffect : ShaderEffect
{
    public MyEffect()
    {
        PixelShader = new PixelShader
        {
            UriSource = new Uri("pack://application:,,,/MyAssembly;component/Shaders/MyEffect.ps")
        };
        UpdateShaderValue(InputProperty);
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (effect.PixelShader == null) throw new InvalidOperationException("ShaderEffect must have a PixelShader set before use.");

Type guard

static bool HasPixelShader(ShaderEffect e) => e?.PixelShader != null;

Prevention

When it happens

Trigger: A ShaderEffect subclass is used in a visual tree and UpdateResource/ManualUpdateResource runs while the PixelShader property has never been set (or was set to null), e.g. the subclass constructor forgot to assign PixelShader or set it after the effect was already attached to an element.

Common situations: Custom shader effects where the .ps bytecode was not embedded/loaded (pack URI wrong, resource missing), subclasses that expose a settable PixelShader which a caller nulls, or an effect attached to an element before deferred shader initialization completes.

Related errors


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

Appendix: source

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

                        ReleaseResource(oldBrush, channel);
                        AddRefResource(newBrush, channel);
                    }
                }
            }

            _samplerData[position] = newSampler;
        }

        private void ManualUpdateResource(DUCE.Channel channel, bool skipOnChannelCheck)
        {
            // If we're told we can skip the channel check, then we must be on channel
            Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel));

            if (skipOnChannelCheck || _duceResource.IsOnChannel(channel))
            {
                if (PixelShader == null)
                {
                    throw new InvalidOperationException(SR.Effect_ShaderPixelShaderSet);
                }

                checked
                {
                    DUCE.MILCMD_SHADEREFFECT data;
                    data.Type = MILCMD.MilCmdShaderEffect;
                    data.Handle = _duceResource.GetHandle(channel);

                    data.TopPadding = _topPadding;
                    data.BottomPadding = _bottomPadding;
                    data.LeftPadding = _leftPadding;
                    data.RightPadding = _rightPadding;

                    data.DdxUvDdyUvRegisterIndex = this.DdxUvDdyUvRegisterIndex;
                    data.hPixelShader = ((DUCE.IResource)PixelShader).GetHandle(channel);

                    unsafe
                    {

View on GitHub (pinned to 81131a70a4)