SubtitleEdit/subtitleedit · error · InvalidOperationException

Failed to create window of type {typeof(TWindow).Name} with

Error message

Failed to create window of type {typeof(TWindow).Name} with constructor param {typeof(TViewModel).Name}

What it means

Thrown by WindowService.ShowDialogAsync<TWindow,TViewModel> when Activator.CreateInstance(typeof(TWindow), viewModel) returns null. Same mechanism as 424/425 but on the modal-dialog path: the ViewModel is resolved from DI, configureViewModel runs, then the window is built via Activator. For reference-type Windows, Activator throws (MissingMethodException / TargetInvocationException) instead of returning null, so the guard is defensive and the live failures come through as those exceptions.

Source

Thrown at src/ui/Logic/WindowsService.cs:197

            await ShowModalAsync(owner, window);

            return window;
        }

        public async Task<TViewModel> ShowDialogAsync<TWindow, TViewModel>(
            Window owner,
            Action<TViewModel>? configureViewModel = null, Action<TWindow>? configureWindow = null)
            where TWindow : Window
            where TViewModel : class
        {
            var viewModel = _serviceProvider.GetRequiredService<TViewModel>();
            configureViewModel?.Invoke(viewModel);

            // Create the window using reflection, passing in the viewModel
            var w = Activator.CreateInstance(typeof(TWindow), viewModel);
            if (w == null)
            {
                throw new InvalidOperationException($"Failed to create window of type {typeof(TWindow).Name} with constructor param {typeof(TViewModel).Name}");
            }

            var window = (TWindow)w;

            window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            configureWindow?.Invoke(window);

            ApplyRightToLeftSettings(window);
            UiTheme.ApplyScaleToWindow(window);

            await ShowModalAsync(owner, window);

            return viewModel;
        }

        /// <summary>
        /// Shows an already-constructed window as a modal dialog with the shared foreground
        /// handling every modal in SE needs: kept above the undocked tool windows (#11971),

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Confirm the dialog window TWindow has a public constructor whose single parameter is the registered TViewModel.
  2. Catch and inspect the TargetInvocationException.InnerException from the Activator call to find the actual missing DI registration or null argument.
  3. Register TViewModel and every service the dialog constructor depends on in the service collection.
  4. Verify the call-site generic order: <TWindow, TViewModel> (window first, viewmodel second).
  5. If the dialog needs extra construction data, pass it through configureViewModel/configureWindow on an already-built instance rather than extra Activator constructor arguments.

Example fix

// before: dialog ctor does not match the resolved ViewModel type
public sealed class FindDialog : Window
{
    public FindDialog(MainViewModel main) { InitializeComponent(); }
}
await windowService.ShowDialogAsync<FindDialog, FindViewModel>(this);

// after: ctor accepts exactly the ViewModel DI resolved
public sealed class FindDialog : Window
{
    public FindDialog(FindViewModel vm) : this()
    {
        DataContext = vm;
    }
    private FindDialog() { InitializeComponent(); }
}
await windowService.ShowDialogAsync<FindDialog, FindViewModel>(this);
Defensive patterns

Strategy: validation

Validate before calling

using System.Reflection;

static bool HasViewModelCtor(Type window, Type vm) =>
    window.GetConstructors().Any(c =>
        c.GetParameters() is { Length: 1 } p && p[0].ParameterType == vm);

if (!HasViewModelCtor(typeof(TWindow), typeof(TViewModel)))
{
    throw new InvalidOperationException(
        $"{typeof(TWindow).Name} must have a public ctor accepting {typeof(TViewModel).Name}.");
}
await windowService.ShowDialogAsync<TWindow, TViewModel>(owner, configureViewModel, configureWindow);

Try / catch

try
{
    return await windowService.ShowDialogAsync<TWindow, TViewModel>(
        owner, configureViewModel, configureWindow);
}
catch (TargetInvocationException ex) when (ex.InnerException != null)
{
    throw ex.InnerException; // unwrap the dialog ctor's real failure
}
catch (MissingMethodException ex)
{
    throw new InvalidOperationException(
        $"{typeof(TWindow).Name} has no public ctor({typeof(TViewModel).Name}).", ex);
}

Prevention

When it happens

Trigger: ShowDialogAsync<TWindow,TViewModel>(owner, configureViewModel, configureWindow) is called for a modal dialog. DI resolves TViewModel and configureViewModel(configureViewModel) runs; then Activator tries TWindow's constructor(TViewModel). It fails when there is no public constructor taking a single TViewModel, or when that constructor throws (a DI service it needs is unregistered or null). The literal null-check throw is the unreachable-for-reference-types tail.

Common situations: A dialog window was created without a public constructor accepting its ViewModel; the registered TViewModel type does not match the constructor parameter type; the dialog constructor calls GetRequiredService on something not registered, throwing inside the ctor; generic arguments at the call site are reversed; a refactor moved or renamed the ViewModel out of sync with the dialog ctor.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/6a9d1ad4dc862ad6. Report an issue: GitHub.