Error handling
Handle errors in your modules using error codes and custom error-handling logic.
Read time 3 minutesLast updated 5 days ago
Learn how to handle errors in your modules.
Error codes
Cloud Code returns a status error if your module throws an exception.
422Use the error code or error type for your error-handling logic, instead of the error message returned from the Cloud Code API error response. Error messages can change in the future, but error codes and type remain the same.
Error wrapping
Wrap your code in / blocks to handle errors. If an error occurs, you can log it and return an error to the client.
trycatchFor example, you can have a non-wrapped function:
[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 / blocks to handle errors, you can return a more specific error message. You can also log the error:
trycatch[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"] } ]}
To get more details about the error, do the following to check the logs:
- In the Unity Dashboard, go to Development > Products.
- Select Cloud Code.
- Select Logs.
Error handling with batch requests
For more information about batch requests, refer to Batch requests.
Status codes
Every time a Cloud Code C# SDK returns an unsuccessful status code, the SDK throws an exception. You can use this exception to get the status code and error message.
ApiExceptionYou can catch the exception and handle it, or log and rethrow the error. This means you don't have to check for the status code in the object.
ApiExceptionApiResponseUnhandled errors
Cloud Code can't handle exceptions that result from memory leaks. If your module exceeds the 256 MB memory limit, the worker process crashes and restarts, and any function call in progress on that worker fails.
Cloud Code can't handle exceptions for patterns. Always return a or . For best practices in asynchronous programming, refer to the official Microsoft documentation.
async voidTaskTask<T>Logging
To help you debug your modules, you can log errors and warnings with the interface.
ILoggerCloud Code automatically adds attributes like the , and to the logs, so you don't need to add them to your log messages.
playerIdenvironmentIdprojectIdusing System;using System.Threading.Tasks;using Microsoft.Extensions.Logging;using Unity.Services.CloudCode.Apis;using Unity.Services.CloudCode.Apis.Extensions;using Unity.Services.CloudCode.Core;using Unity.Services.CloudCode.Shared;using Unity.Services.Economy.Model;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.AddGameApiClient(); } }}
You can log messages at different levels. These levels can help you query logs in the Unity Dashboard.
_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, do the following:
- In the Unity Dashboard, go to Development > Products.
- Select Cloud Code.
- Select Logs.
For more information, refer to Emit logs.