tui-cs/Terminal.Gui · critical · InvalidOperationException

Cannot use legacy static Application model (Application.Init

Error message

Cannot use legacy static Application model (Application.Init/ApplicationImpl.Instance) after using modern instance-based model (Application.Create). Use only one model per process.

What it means

Thrown inside Init when the legacy static Application singleton (_instance) is being initialized but the process already used the modern instance-based model (Application.Create). Terminal.Gui v2 forbids mixing the two models because they share global driver/main-loop state; using both would corrupt the synchronization context and driver ownership. The error string is ERROR_LEGACY_AFTER_MODERN.

Source

Thrown at Terminal.Gui/App/ApplicationImpl.Lifecycle.cs:48

        }

        MainThreadId = Thread.CurrentThread.ManagedThreadId;

        Trace.Lifecycle (MainThreadId?.ToString (), "Init", $"driverName: {driverName}");

        // In Application.Init(), before starting the input thread:
        // Pre-warm the Wcwidth static cache to prevent ZeroTable._lookup race condition
        // See: https://github.com/spectreconsole/wcwidth/issues/11
        _ = UnicodeCalculator.GetWidth (new Rune ('A'));

        // Thread-safe fence check: Ensure we're not mixing application models
        // Use lock to make check-and-set atomic
        lock (_modelUsageLock)
        {
            // If this is a legacy static instance and instance-based model was used, throw
            if (this == _instance && ModelUsage == ApplicationModelUsage.InstanceBased)
            {
                throw new InvalidOperationException (ERROR_LEGACY_AFTER_MODERN);
            }

            // If this is an instance-based instance and legacy static model was used, throw
            if (this != _instance && ModelUsage == ApplicationModelUsage.LegacyStatic)
            {
                throw new InvalidOperationException (ERROR_MODERN_AFTER_LEGACY);
            }

            // If no model has been set yet, set it now based on which instance this is
            if (ModelUsage == ApplicationModelUsage.None)
            {
                ModelUsage = this == _instance ? ApplicationModelUsage.LegacyStatic : ApplicationModelUsage.InstanceBased;
            }
        }

        if (!string.IsNullOrWhiteSpace (driverName))
        {
            _driverName = driverName;

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Pick one model per process and use it consistently: prefer the modern instance-based model (Application.Create).
  2. If a dependency forces the legacy model, run your app with the legacy static API (Application.Init/Run/Shutdown) throughout.
  3. Isolate conflicting code into a subprocess so each process uses only one model.
  4. Call ApplicationImpl.ResetModelUsageTracking() (test-only) only in controlled test scenarios to reset the fence.

Example fix

// before
using var app = Application.Create ().Init ();
// ... later ...
Application.Init (); // legacy static after modern — throws

// after — use only the modern model
using var app = Application.Create ().Init ();
app.Run<MyWindow> ();
Defensive patterns

Strategy: validation

Validate before calling

// Pick one model at process start and never mix.
// Modern (recommended):
using var app = Application.Create ().Init ();
// Do NOT call Application.Init() anywhere after this.

Prevention

When it happens

Trigger: Calling Application.Init() (legacy static facade) after Application.Create() was already invoked elsewhere in the same process; a third-party library or test helper that uses the legacy static API while the host app uses the modern instance-based API.

Common situations: Integrating a library written against the v1/legacy static API into a v2 app that uses Application.Create(); mixing UICatalog-style instance code with legacy snippets; a dependency that internally calls Application.Init.

Related errors


AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13). Data as JSON: /api/errors/187cd46740009715. Report an issue: GitHub.