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
- Set a tone-mapping operator before rendering, e.g. toneMap.Operator = new ACESOperator();
- Pick the operator matching your desired look (ACES, Hable/Uncharted2, Reinhard) in scene setup.
- 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
- Always set Operator at ToneMap construction time
- Validate the full transform pipeline before first render
- Use object initializers so required fields are set inline
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
- A disposed operation cannot be rollbacked.
- A disposed operation cannot be rollforwarded.
- Already initialized.
- assetItem must be an absolute path
- Begin must be called before functionName
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)