stride3d/stride · error · InvalidOperationException

Converter is null but following Converter is not null

Error message

Converter{i} is null but following Converter{i + 1} is not null

What it means

ChainedConverter.ConvertBack walks the converters in reverse; a null converter before conversion starts is skipped, but once conversion has started, encountering a null converter followed by a non-null one is an invalid chain layout. ConvertBack throws this InvalidOperationException to flag the inconsistent configuration.

Solutions

  1. Remove or null out all converters after the gap so non-null converters are contiguous from Converter0
  2. Fill the gap with an appropriate converter (or a pass-through) if the later converter is needed
  3. Mark the binding OneWay to avoid ConvertBack if back-conversion is undesired
  4. Restructure into multiple smaller chained converters without holes

Example fix

// before
var chained = new Chained { Converter = c0, Converter1 = null, Converter2 = c2 };
// after
var chained = new Chained { Converter = c0, Converter1 = passThrough, Converter2 = c2 };
Defensive patterns

Strategy: type-guard

Validate before calling

object[] converters = { ch.Converter, ch.Converter1, ch.Converter2 };
if (!IsContiguousPrefix(converters)) throw new InvalidOperationException("Converter chain has a null gap");

Type guard

static bool IsContiguousPrefix(object[] converters) => converters.TakeWhile(c => c != null).Count() == converters.Count(c => c != null);

Try / catch

try { var back = chained.ConvertBack(value, targetType, param, culture); } catch (InvalidOperationException ex) when (ex.Message.Contains("following Converter")) { return Binding.DoNothing; }

Prevention

When it happens

Trigger: A converter chain where ConverterN is null while ConverterN+1 is non-null, exercised on a two-way binding so ConvertBack runs (e.g. Converter0 set, Converter1 null, Converter2 set, and the target writes back to the source).

Common situations: One-way bindings set up in XAML that later become TwoWay; the hole in the chain goes unnoticed until an edit triggers ConvertBack; renumbering mistakes after removing a converter.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Avalonia/Converters/Chained.cs:285

        }
        return output;
    }

    /// <inheritdoc/>
    public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        var output = value;

        var conversionStarted = false;

        for (var i = MaxConverterCount - 1; i >= 0; --i)
        {
            var input = output;
            if (converters[i] == null)
            {
                if (!conversionStarted)
                    continue;
                throw new InvalidOperationException($"Converter{i} is null but following Converter{i + 1} is not null");
            }

            conversionStarted = true;

            var type = converterTargetType[i] ?? (i == 0 ? targetType : typeof(object));
            output = converters[i]!.ConvertBack(input, type, converterParameters[i], culture);
        }
        return output;
    }
}

View on GitHub (pinned to 96fad776d2)