QuantConnect/Lean · error · RegressionTestException

{Time} - Unexpected symbol changed event new symbol: {change

Error message

{Time} - Unexpected symbol changed event new symbol: {changedEvent}

What it means

The companion assertion to the old-symbol check: after a continuous-future rollover, the SymbolChangedEvent.NewSymbol must equal the contract that Lean now reports as _continuousContract.Mapped. A mismatch means the event's reported destination contract differs from the engine's current mapped contract, signalling a divergence between the event stream and the continuous-contract security state.

Source

Thrown at Algorithm.CSharp/BasicTemplateEurexFuturesAlgorithm.cs:85

        {
            foreach (var changedEvent in slice.SymbolChangedEvents.Values)
            {
                if (++_mappingsCount > 1)
                {
                    throw new RegressionTestException($"{Time} - Unexpected number of symbol changed events (mappings): {_mappingsCount}. " +
                        $"Expected only 1.");
                }

                Debug($"{Time} - SymbolChanged event: {changedEvent}");

                if (changedEvent.OldSymbol != _mappedSymbol.ID.ToString())
                {
                    throw new RegressionTestException($"{Time} - Unexpected symbol changed event old symbol: {changedEvent}");
                }

                if (changedEvent.NewSymbol != _continuousContract.Mapped.ID.ToString())
                {
                    throw new RegressionTestException($"{Time} - Unexpected symbol changed event new symbol: {changedEvent}");
                }

                // Let's trade the previous mapped contract, so we can hold it until expiration for testing
                // (will be sooner than the new mapped contract)
                _contractToTrade = _mappedSymbol;
                _mappedSymbol = _continuousContract.Mapped;
            }

            // Let's trade after the mapping is done
            if (_contractToTrade != null && _boughtQuantity == 0 && Securities[_contractToTrade].Exchange.ExchangeOpen)
            {
                Buy(_contractToTrade, 1);
            }

            if (_contractToTrade != null && slice.Delistings.TryGetValue(_contractToTrade, out var delisting))
            {
                if (delisting.Type == DelistingType.Delisted)
                {

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Validate the continuous-contract configuration (mapping mode, depth offset, normalization) against the expected data set.
  2. Check that only one mapping event occurs in the backtest (the _mappingsCount > 1 guard at line 70 has not tripped).
  3. Confirm EUREX futures data completeness; a missing destination contract makes NewSymbol fall back unexpectedly.
  4. Re-read _continuousContract.Mapped at event time rather than caching, to compare against current engine state.
Defensive patterns

Strategy: validation

Validate before calling

foreach (var changedEvent in slice.SymbolChangedEvents.Values)
{
    var currentMapped = _continuousContract.Mapped.ID.ToString();
    if (changedEvent.NewSymbol != currentMapped)
    {
        Log($"{Time} - Mapping dest mismatch: event={changedEvent.NewSymbol} mapped={currentMapped}");
    }
}

Prevention

When it happens

Trigger: A SymbolChangedEvent fires and changedEvent.NewSymbol != _continuousContract.Mapped.ID.ToString(). The destination contract in the event does not match the live continuous-contract Mapped symbol at the moment the event is processed.

Common situations: Engine version change alters how/when Mapped is updated relative to event emission; multiple mapping events queued in one slice; data change shifts the destination contract; contractDepthOffset adjusted so a different expiry becomes the new mapped contract.

Related errors


AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13). Data as JSON: /api/errors/9780493e24b1fa8e. Report an issue: GitHub.