babalae/better-genshin-impact · error · InvalidDataException

根实例连接响应缺少数据。

Error message

根实例连接响应缺少数据。

What it means

Thrown in RootConnectionLoopAsync when the connection.open response from the root instance deserializes to a null ConnectionOpenResponse. The code calls EnsureSuccessfulResponse(openResult) first (which passes), then attempts openResult.Data?.ToObject<ConnectionOpenResponse>(Serializer). If Data is null or cannot be deserialized to ConnectionOpenResponse, the cast yields null and this error fires.

Solutions

  1. Ensure the child and root processes run the same build version so ConnectionOpenResponse schema matches exactly.
  2. Inspect the root-side CreateOpenResponse to confirm it always builds a ConnectionOpenResponse with all required fields.
  3. Log openResult.Data?.ToString() before the ToObject call to see the actual JSON the root sent.
  4. If developing a protocol change, update ConnectionOpenResponse in all peers and verify round-trip serialization with the CamelCase resolver.
Defensive patterns

Strategy: try-catch

Try / catch

// In RootConnectionLoopAsync, this is already caught by:
catch (Exception exception) when (exception is InvalidOperationException or InvalidDataException)
{
    _logger.LogError(exception, "不可恢复的协议错误,停止重连");
    RequestApplicationShutdown();
    return;
}

Prevention

When it happens

Trigger: The root instance returned a successful connection.open response (Success == true) but the Data JObject is missing, is null, or has a schema that doesn't map to ConnectionOpenResponse (missing Disposition, AssignedType, RootProcessId, RootSessionId fields or wrong casing). Since the serializer uses CamelCasePropertyNamesContractResolver, a field-name mismatch between the request/response model and the JSON would cause silent null deserialization.

Common situations: Version mismatch between the child and root where ConnectionOpenResponse was modified (fields renamed, added, or removed); a root instance bug that returns a success response without populating Data; Newtonsoft.Json deserialization returning null due to a JSON type mismatch (e.g., RootProcessId sent as a string instead of int).

Related errors


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

Appendix: source

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

                    connection.Start(cancellationToken);

                    var openResult = await connection.SendRequestAsync(
                        InstanceOperations.ConnectionOpen,
                        new ConnectionOpenRequest
                        {
                            RequestedType = Context.InstanceType,
                            RestartFromProcessId = restartFromProcessId,
                            Arguments = includeActivationArguments
                                ? Environment.GetCommandLineArgs()
                                : []
                        },
                        RequestTimeout,
                        cancellationToken).ConfigureAwait(false);
                    EnsureSuccessfulResponse(openResult);
                    openResponse =
                        openResult.Data?.ToObject<ConnectionOpenResponse>(
                            InstanceIpcProtocol.Serializer)
                        ?? throw new InvalidDataException("根实例连接响应缺少数据。");
                }

                if (openResponse.Disposition
                    == ConnectionOpenDisposition.ActivationForwarded)
                {
                    RequestApplicationShutdown();
                    return;
                }
                if (openResponse.AssignedType != Context.InstanceType)
                {
                    throw new InvalidOperationException(
                        $"根实例分配了不匹配的客户端类型:{openResponse.AssignedType}。");
                }

                Context.SetRootSessionId(openResponse.RootSessionId);
                connection.RemoteEndpoint = new InstanceEndpoint
                {
                    InstanceType = BetterGiInstanceType.Primary,

View on GitHub (pinned to a7cb36712d)