stride3d/stride · error · InvalidOperationException

Operator cannot be null on this instance

Error message

Operator cannot be null on this instance

What it means

ToneMap.UpdateParameters throws InvalidOperationException when the Operator property is null. Tone mapping requires a ToneMapOperator to compute the tone curve; without it the parameter update cannot proceed. Unlike argument checks, this indicates the instance itself was misconfigured before rendering.

Solutions

  1. Set a tone-mapping operator before rendering, e.g. toneMap.Operator = new ACESOperator();
  2. Pick the operator matching your desired look (ACES, Hable/Uncharted2, Reinhard) in scene setup.
  3. If Operator was nulled dynamically, restore it or disable the ToneMap transform.

Example fix

// before
var toneMap = new ToneMap();
group.PostTransforms.Add(toneMap); // Operator null
// after
var toneMap = new ToneMap { Operator = new ACESOperator() };
group.PostTransforms.Add(toneMap);
Defensive patterns

Strategy: validation

Validate before calling

if (toneMap.Operator == null)
    toneMap.Operator = new ACESOperator();
group.PostTransforms.Add(toneMap);

Type guard

bool IsRenderable(ToneMap t) => t?.Operator != null;

Try / catch

try { group.Prepare(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Operator cannot be null"))
{ toneMap.Operator = new ACESOperator(); }

Prevention

When it happens

Trigger: Adding a ToneMap transform to a ColorTransformGroup and rendering without ever setting its Operator property, or setting Operator to null after construction.

Common situations: Creating ToneMap via a parameterless path or deserialization that skips Operator assignment; copying transform setups where only some fields were carried over; forgetting to choose between ACES/Hable/Reinhard operators.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/488f7104bb605e75. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Rendering/Rendering/Images/ColorTransforms/ToneMap/ToneMap.cs:190

        [DefaultValue(0f)]
        public float Brightness
        {
            get => Parameters.Get(ToneMapShaderKeys.Brightness);
            set => Parameters.Set(ToneMapShaderKeys.Brightness, value);
        }

        public override void PrepareParameters(ColorTransformContext context, ParameterCollection parentCollection, string keyRoot)
        {
            base.PrepareParameters(context, parentCollection, keyRoot);

            Operator.PrepareParameters(context, Parameters, ".ToneMapOperator");
        }

        public override void UpdateParameters(ColorTransformContext context)
        {
            if (Operator == null)
            {
                throw new InvalidOperationException("Operator cannot be null on this instance");
            }

            // Update the luminance
            var elapsedTime = timer.Elapsed;
            timer.Restart();

            var luminanceResult = context.SharedParameters.Get(LuminanceEffect.LuminanceResult);

            // Get the average luminance
            float adaptedLum = luminanceResult.AverageLuminance;
            if (TemporalAdaptation)
            {
                // Get adapted luminance
                // From "Perceptual effects in real-time tone mapping" by Grzegorz Krawczyk, Karol Myszkowski, Hans-Peter Seidel, p. 3, Equation 5
                adaptedLum = (float)(previousLuminance + (luminanceResult.AverageLuminance - previousLuminance) * (1.0 - Math.Exp(-elapsedTime.TotalSeconds * AdaptationRate)));
                previousLuminance = adaptedLum;
            }

View on GitHub (pinned to 96fad776d2)