Skip to main content

Migration Guides

Note: ResponseType has changed shape twice. It was a plain enum through Core.Constants v10.0.1, a record in v10.0.2–v10.0.3, and is a plain enum again from Core.Constants v10.0.4 onward. With the current enum, read the semantic label with ex.ResponseType.ToString(), not ex.ResponseType.Value.

v10.1.0 → v10.2.0​

This release is additive for call sites. It adds PaymentRequiredException for HTTP 402 and depends on RA.Utilities.Core.Constants 10.1.1.

Breaking Change: None​

Existing exception types, constructors, and default messages are unchanged, so an upgrade requires no code changes.

New exception​

TypeConstructorsResponseType
PaymentRequiredException() · (string message) · (int errorCode, string? message = null)ResponseType.PaymentRequired

Use it when the caller is authenticated but the resource requires payment. Do not use it for authentication (401), permission (403), or rate limiting (429).

throw new PaymentRequiredException("This report is available on paid plans.");

Dependency​

RA.Utilities.Core.Exceptions 10.2.0 ships with a dependency on RA.Utilities.Core.Constants 10.1.1, which provides BaseResponseCode.PaymentRequired (402), BaseResponseMessages.PaymentRequired, and the ResponseType.PaymentRequired member. If your project pins the Constants package directly, use 10.1.1 or later.


v10.0.4 → v10.1.0​

This release is additive for call sites. It adapts the package to RA.Utilities.Core.Constants v10.0.4+, adds convenience constructors, and makes the default-message behavior explicit.

Breaking Change: None​

Existing calls such as new NotFoundException("Product", id), new ForbiddenException(403, "…"), and new BadRequestException(errors) compile and behave the same. The signature changes are limited to the nullability annotation of message (string → string?) and the split of the optional errorCode into a dedicated entity/value/message overload; neither affects source compatibility.

Why this change?​

RA.Utilities.Core.Constants v10.0.4 changed every field from const to static readonly. C# requires a compile-time constant for a default parameter value, so defaults such as string message = BaseResponseMessages.NotFound no longer compile. v10.1.0 expresses the same behavior with a nullable sentinel that is resolved at runtime:

public NotFoundException(int errorCode, string? message = null)
: base(errorCode, ResponseType.NotFound, message ?? BaseResponseMessages.NotFound)
{
}

The release also removes the need to pass a redundant error code when you only want an entity-aware exception or a generic one.

What changed​

Aspectv10.0.4v10.1.0
message parameter typestringstring? (default null)
Default message sourceCompile-time constant argumentBaseResponseMessages.* resolved at runtime
message: nullPassed through (no package fallback)Package default message
message: ""Empty messageEmpty message (preserved)
NotFoundException without entitynew NotFoundException(BaseResponseCode.NotFound)new NotFoundException()
ConflictException without entitynew ConflictException(BaseResponseCode.Conflict)new ConflictException()
Entity + custom messagenew NotFoundException(entity, value, message: "…")Supported (no errorCode required)
BadRequestException single errornew BadRequestException(new[] { error })new BadRequestException(error)

New constructors​

TypeNew in v10.1.0
NotFoundExceptionNotFoundException() · NotFoundException(string entity, object value, string? message)
ConflictExceptionConflictException() · ConflictException(string entity, object value, string? message)
BadRequestExceptionBadRequestException(ValidationError error) · BadRequestException(ValidationError error, int errorCode, string? message = null)
All exceptionsmessage is optional and nullable on the error-code overloads

Migration Steps​

1. No code changes required​

Upgrade the package and rebuild:

dotnet add package RA.Utilities.Core.Exceptions --version 10.1.0

2. Optionally simplify redundant calls​

Before:

return new NotFoundException(BaseResponseCode.NotFound);
return new ConflictException(BaseResponseCode.Conflict);
return new BadRequestException(new[] { error });

After:

return new NotFoundException();
return new ConflictException();
return new BadRequestException(error);

3. Audit explicit empty messages​

This behavior is unchanged, but it surprises callers: "" is a real message and is never replaced by the default. If you passed "" while expecting the package default, omit the argument instead.

Before:

throw new ForbiddenException(errorCode: 4030, message: ""); // empty message

After:

throw new ForbiddenException(errorCode: 4030); // BaseResponseMessages.Forbidden
Empty is not the same as omitted

message ?? default only defaults when the value is null. An explicit "" is preserved:

new ForbiddenException(4030, "").Message; // ""
new ForbiddenException(4030).Message; // "You do not have permission to access this resource."

Dependency​

RA.Utilities.Core.Exceptions 10.1.0 ships with a dependency on RA.Utilities.Core.Constants 10.0.5. If your project pins the Constants package directly, use 10.0.5 or later so the static readonly fields and the ResponseType enum used here are available.


v10.0.3 → v10.0.4​

This release modernizes the exception base class and aligns the hierarchy with the ResponseType type from RA.Utilities.Core.Constants (a record in Core.Constants v10.0.2–v10.0.3, and a plain enum from v10.0.4 onward).

Breaking Change: ErrorCode changed from string to int​

The error code property and constructor parameter is now an int (typically an HTTP status code), not a string.

Before (v10.0.3):

throw new ConflictException(
errorCode: nameof(BaseResponseCode.Conflict), // string
message: "A conflict occurred."
);

After (v10.0.4):

throw new ConflictException(
errorCode: BaseResponseCode.Conflict, // int = 409
message: "A conflict occurred."
);

Breaking Change: RaBaseException constructor signature changed​

The base constructor now accepts (int errorCode, ResponseType errorType, string message) instead of (string errorCode, string message, int responseCode).

Before (v10.0.3):

public class PaymentFailedException : RaBaseException
{
public PaymentFailedException(string reason)
: base("PAYMENT_FAILED", $"Payment failed: {reason}", 400)
{
}
}

After (v10.0.4):

public class PaymentFailedException : RaBaseException
{
public PaymentFailedException(string reason)
: base(400, ResponseType.BadRequest, $"Payment failed: {reason}")
{
}
}

Breaking Change: ResponseCode removed, ResponseType added​

RaBaseException.ResponseCode (an int) has been removed and replaced with ResponseType (a record at the time; a plain enum from Core.Constants v10.0.4 onward).

Before (v10.0.3):

catch (RaBaseException ex)
{
int statusCode = ex.ResponseCode; // e.g., 404
string errorCode = ex.ErrorCode; // e.g., "NotFound"
}

After (v10.0.4):

catch (RaBaseException ex)
{
int statusCode = ex.ErrorCode; // e.g., 404
string responseType = ex.ResponseType.ToString(); // e.g., "NotFound"
}

Breaking Change: ValidationErrors renamed to ValidationError​

The class representing a single validation error has been renamed from ValidationErrors (plural) to ValidationError (singular).

Before (v10.0.3):

var error = new ValidationErrors
{
PropertyName = "Email",
ErrorMessage = "Invalid email format."
};

throw new BadRequestException(new[] { error });

After (v10.0.4):

var error = new ValidationError("Invalid email format.")
{
PropertyName = "Email"
};

throw new BadRequestException(new[] { error });

Note: ValidationError now requires errorMessage as a constructor argument. Properties PropertyName, ErrorCode, AttemptedValue, and ExpectedValue are now nullable (string? / object?).

New Features in v10.0.4​

  • GatewayTimeoutException: New exception class for HTTP 504 Gateway Timeout scenarios.
  • TooManyRequestsException and ServiceUnavailableException: New exception classes for HTTP 429 and 503.
  • Parameterless constructors: ForbiddenException, UnauthorizedException, UnprocessableException, GatewayTimeoutException, TooManyRequestsException, and ServiceUnavailableException now have parameterless constructors with sensible defaults.
  • string message constructors: These exceptions now accept a single string message parameter.
  • init accessors: All exception properties now use { get; init; } for immutability after construction.

Full Changelog​

See the package release notes for a complete version history.