stride3d/stride · error · InvalidOperationException

ShadowObject is not enabled. You need to enable it in order…

Error message

ShadowObject is not enabled. You need to enable it in order to use this method. Note also that ShadowObject has a performance cost at runtime

What it means

ShadowObject is an opt-in debugging/reflection feature whose per-instance shadow dictionaries add runtime overhead, so it is disabled by default via ShadowObject.Enable. GetOrCreate() throws InvalidOperationException when the feature has not been enabled, protecting users from silently paying the performance cost.

Solutions

  1. Set ShadowObject.Enable = true before calling GetOrCreate
  2. Guard the call site: only call GetOrCreate when ShadowObject.Enable is true
  3. Remove the ShadowObject usage if the runtime performance cost is not acceptable in production code

Example fix

// before
var shadow = ShadowObject.GetOrCreate(myObject);
// after
ShadowObject.Enable = true;
var shadow = ShadowObject.GetOrCreate(myObject);
Defensive patterns

Strategy: validation

Validate before calling

if (!ShadowObject.Enable)
    throw new InvalidOperationException("Enable ShadowObject before calling GetOrCreate");

Try / catch

try { var shadow = ShadowObject.GetOrCreate(obj); }
catch (InvalidOperationException) { /* feature disabled: skip shadow logic */ }

Prevention

When it happens

Trigger: Calling ShadowObject.GetOrCreate(instance) without first setting ShadowObject.Enable = true.

Common situations: Using debugger visualizers or design-time tools that rely on ShadowObject in a host process where no one enabled it; writing diagnostics code copied from a sample that had a static initializer enabling the flag.

Related errors


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

Appendix: source

Thrown at sources/core/Stride.Core.Design/Reflection/ShadowObject.cs:64

    /// <returns>The shadow instance or <c>null</c> if none</returns>
    public static ShadowObject? Get(object? instance)
    {
        if (!Enable || instance == null) return null;
        Shadows.TryGetValue(instance, out var shadow);
        return shadow;
    }

    /// <summary>
    /// Gets the <see cref="ShadowObject"/> instance. Creates it if it does not exist.
    /// </summary>
    /// <param name="instance">The live instance.</param>
    /// <returns>The shadow instance</returns>
    [return: NotNullIfNotNull(nameof(instance))]
    public static ShadowObject? GetOrCreate(object? instance)
    {
        if (!Enable)
        {
            throw new InvalidOperationException("ShadowObject is not enabled. You need to enable it in order to use this method. Note also that ShadowObject has a performance cost at runtime");
        }

        if (instance == null) return null;
        return Shadows.GetValue(instance, _ => new ShadowObject());
    }

    /// <summary>
    /// Copies all dynamic properties from an instance to another instance.
    /// </summary>
    /// <param name="fromInstance">The instance to copy the shadow attributes from</param>
    /// <param name="toInstance">The instance to copy the shadow attributes to</param>
    public static void Copy(object fromInstance, object toInstance)
    {
        if (!Enable) return;
#if NET6_0_OR_GREATER
        ArgumentNullException.ThrowIfNull(fromInstance);
        ArgumentNullException.ThrowIfNull(toInstance);
#else

View on GitHub (pinned to 96fad776d2)