babalae/better-genshin-impact · critical · InvalidOperationException

根实例未取得首个命名管道服务端。

Error message

根实例未取得首个命名管道服务端。

What it means

Thrown in InstanceService.StartAsync when the process is the Primary instance but _bootstrap.TakeFirstServer() returns null. TakeFirstServer atomically transfers the first NamedPipeServerStream (created during InstanceBootstrap.Initialize) to InstanceService exactly once; returning null means no server was ever created or it was already consumed.

Source

Thrown at BetterGenshinImpact/Service/Instance/InstanceService.cs:90

    public event EventHandler<WebViewMessageReceivedEventArgs>? WebViewMessageReceived;

    public InstanceContext Context => _bootstrap.Context;

    public bool IsGameMouseModeEnabled =>
        _relativeMouseMessageHandler.IsGameMouseModeEnabled;

    public void SetGameMouseModeEnabled(bool enabled)
    {
        _relativeMouseMessageHandler.SetGameMouseModeEnabled(enabled);
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        if (Context.InstanceType == BetterGiInstanceType.Primary)
        {
            var firstServer = _bootstrap.TakeFirstServer()
                              ?? throw new InvalidOperationException(
                                  "根实例未取得首个命名管道服务端。");
            _acceptLoopTask = AcceptLoopAsync(
                firstServer,
                _lifetimeCancellationTokenSource.Token);
        }
        else
        {
            _rootConnectionLoopTask = RootConnectionLoopAsync(
                _bootstrap.TakeFirstRootConnection(),
                _lifetimeCancellationTokenSource.Token);
        }

        _logger.LogInformation(
            "实例 IPC v2 已启动:{InstanceType},进程 {ProcessId},Session {SessionId},根管道 {PipeName}",
            Context.InstanceType,
            Context.ProcessId,
            Context.WindowsSessionId,
            Context.RootPipeName);

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Verify InstanceBootstrap.Initialize() is called and fully completed before InstanceService.StartAsync — check the startup sequence in App.xaml.cs or the host builder.
  2. Ensure StartAsync is only called once by the generic host (it should be — check for manual invocations).
  3. Inspect InstanceBootstrap.Initialize for the Primary branch to confirm it always assigns _firstServer via InstancePipeFactory.CreateServer before returning.
  4. If the error recurs, add logging in InstanceBootstrap.Initialize to confirm the Primary path executed and _firstServer was set.
Defensive patterns

Strategy: validation

Validate before calling

// Before StartAsync, verify bootstrap state
if (Context.InstanceType == BetterGiInstanceType.Primary && bootstrap is { } b)
{
    // TakeFirstServer is one-shot; ensure it hasn't been called yet
    // by verifying Initialize completed successfully
}

Prevention

When it happens

Trigger: InstanceBootstrap.Initialize determined this process should be Primary (won the FirstPipeInstance race) but failed to create or retain the first server stream — possibly due to a pipe creation error that was swallowed, or StartAsync was called twice (second TakeFirstServer returns null). Alternatively, the bootstrap was never initialized before StartAsync ran, or initialization logic has a bug where the Primary path doesn't populate _firstServer.

Common situations: Startup ordering bug where InstanceService.StartAsync runs before InstanceBootstrap.Initialize completes; a race where the bootstrap disposed the server during ActivationForwarded processing but InstanceType was still Primary; calling StartAsync more than once; a DI misconfiguration that creates two InstanceService instances both calling TakeFirstServer.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/f82809718b4efc24. Report an issue: GitHub.