Error handling

Learn how to handle errors in your modules.

Error codes

Cloud Code returns a 422 status error if your module throws an exception.

Use the error code or error type instead of the error message returned from the Cloud Code API error response for your error handling logic. Error messages might change in the future, but error codes and type will remain the same.

Error wrapping

Wrap your code in try/catch blocks to handle errors. If an error occurs, you can log it and return an error to the client.

For example, you can have a non wrapped function:

C#

[CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        return await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,  ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));
    }

The non wrapped function returns a generic error:

{
  "type": "problems/invocation",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Invocation Error",
  "instance": null,
  "code": 9009,
  "details": [
    {
      "message": "Error executing Cloud Code function. Exception type: ApiException. Message: Bad Request",
      "name": "ScriptRunner.Exceptions.CloudCodeRuntimeException",
      "stackTrace": [
        "at Unity.Services.CloudCode.Shared.HttpApiClient.ToApiResponse[T](HttpResponseMessage response)",
        "at Unity.Services.CloudCode.Shared.HttpApiClient.SendAsync[T](String path, HttpMethod method, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken)",
        "at Unity.Services.Economy.Api.EconomyCurrenciesApi.IncrementPlayerCurrencyBalanceAsync(IExecutionContext executionContext, String accessToken, String projectId, String playerId, String currencyId, CurrencyModifyBalanceRequest currencyModifyBalanceRequest, String configAssignmentHash, String unityInstallationId, String analyticsUserId, CancellationToken cancellationToken)",
        "at Sample.HelloWorld.IncrementBalanceUnhandled(IGameApiClient gameApiClient, IExecutionContext ctx, String currencyId) in Sample/Main/HelloWorld.cs:line 148"
      ]
    }
  ]
}

If you add the try/catch blocks to handle errors, you can return a more specific error message. You can also log the error:

C#

[CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        try
        {
            return await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,
                ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

        }
        catch (ApiException e)
        {
             _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
            throw new Exception($"Failed to increment balance for playerId {ctx.PlayerId}. Error: {e.Message}");
        }
    }

The wrapped function returns an error message with more detail:

{
    "type": "problems/invocation",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invocation Error",
    "instance": null,
    "code": 9009,
    "details": [
        {
            "message": "Error executing Cloud Code function. Exception type: Exception. Message: Failed to increment balance for playerId 7wCG6G0d1PU6WSVZPG9oQ1op97xd. Error: Bad Request",
            "name": "ScriptRunner.Exceptions.CloudCodeRuntimeException",
            "stackTrace": [
                "at Sample.HelloWorld.IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, String currencyId) in Sample/Main/HelloWorld.cs:line 165"
            ]
        }
    ]
}

You can check the logs in the Unity Cloud Dashboard. To get more details about the error, select Live Ops > Cloud Code > Logs.

Error handling with batch requests

For more information about batch requests, refer to the Batch requests documentation.

Status codes

Every time a Cloud Code C# SDK returns an unsuccessful status code, the SDK throws an ApiException exception. You can use this exception to get the status code and error message.

You can catch the ApiException exception and handle it, or log and rethrow the error. This means you don't have to check for the status code in the ApiResponse object.

Logging

To help you debug your modules, you can log errors and warnings with the ILogger interface.

Cloud Code automatically adds attributes like the playerId, environmentId and projectId to the logs for you, so you don't need to add them to your log messages.

C#

public class HelloWorld
{
    private readonly ILogger<HelloWorld> _logger;
    public HelloWorld(ILogger<HelloWorld> logger)
    {
        _logger = logger;
    }

    [CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        try
        {
           var res =  await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,
                ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

           _logger.LogInformation("Incremented currency {currencyId} balance by {amount}", currencyId, 10);
           return res;

        }
        catch (ApiException e)
        {
            _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
            throw new Exception($"Failed to increment balance for playerId {ctx.PlayerId}. Error: {e.Message}");
        }
    }

    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.Dependencies.AddSingleton(GameApiClient.Create());
        }
    }
}

You can log messages at different levels. These levels can help you query logs in the Unity Cloud Dashboard.

C#

_logger.LogDebug("debug message");
    _logger.LogInformation("info message");
    _logger.LogWarning("warning message");
    _logger.LogError("error message");
    _logger.LogCritical("critical message");

To view and filter your logs, navigate to the Unity Cloud Dashboard and select Live Ops > Cloud Code > Logs.

For more information, refer to Emit logs documentation.