Skip to content

playerConnecting event crashes when performing async database queries in C# #3831

@woozievert

Description

@woozievert

What happened?

When performing async database queries (such as Entity Framework Core or similar ORM operations) inside the playerConnecting event handler, the server crashes or throws exceptions, even when using deferrals.defer() and [FromSource] correctly.
The code is structured according to the official documentation:
`
private async void OnPlayerConnecting(
[FromSource] Player player, string playerName,
dynamic setKickReason, dynamic deferrals)
{
deferrals.defer();

try
{
    // This causes crashes/exceptions
    var ban = await BanRepo.FindActiveBanAsync(license, ip);
    
    if (ban != null)
    {
        deferrals.done($"You are banned. Reason: {ban.Reason}");
        return;
    }
    
    deferrals.done();
}
catch (Exception ex)
{
    Logger.Error("Ban check failed", ex);
    deferrals.done("Server error");
}

}
`
The database query (FindActiveBanAsync) performs a typical async operation (e.g., DbContext.Bans.Where(...).FirstOrDefaultAsync()), but this causes the server to crash or become unstable.

Expected result

According to the official playerConnecting documentation, after calling deferrals.defer(), it should be safe to perform async operations: > "Assuming you have a function called IsBanned of type Task - normally you'd do a database query here, which might take some time" The documentation example shows: if (await IsBanned(licenseIdentifier)){ deferrals.done($"You have been kicked...");} This suggests async database queries should work, but in practice they cause crashes.

Reproduction steps

  1. Create a server-side C# resource with Entity Framework Core or any async database library

  2. Set up a repository method that performs an async database query:
    public async Task<BanData> FindActiveBanAsync(string license, string ip) { return await _dbContext.Bans .Where(b => (b.License == license || b.IpAddress == ip) && (!b.ExpiresAt.HasValue || b.ExpiresAt.Value > DateTime.UtcNow)) .FirstOrDefaultAsync(); }

  3. Call this method in the playerConnecting handler:
    `private async void OnPlayerConnecting(
    [FromSource] Player player, string playerName,
    dynamic setKickReason, dynamic deferrals)
    {
    deferrals.defer();

    string license = player.Identifiers.FirstOrDefault(id => id.StartsWith("license:"));

    deferrals.update("Checking ban status...");

    var ban = await BanRepo.FindActiveBanAsync(license, null);

    if (ban != null)
    {
    deferrals.done($"Banned: {ban.Reason}");
    return;
    }

    deferrals.done();
    }`

  4. Start the server and attempt to connect

  5. Server crashes or throws exceptions during the database query

Importancy

There's a workaround

Area(s)

FiveM, ScRT: C#

Specific version(s)

FiveM 25963

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    ScRT: C#Issues/PRs related to either C# scripting runtimesbugtriageNeeds a preliminary assessment to determine the urgency and required action

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions