Migration Guides
Note:
ResponseTypehas changed shape twice. It was a plain enum through Core.Constants v10.0.1, arecordin 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 withex.ResponseType.ToString(), notex.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
| Type | Constructors | ResponseType |
|---|---|---|
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
| Aspect | v10.0.4 | v10.1.0 |
|---|---|---|
message parameter type | string | string? (default null) |
| Default message source | Compile-time constant argument | BaseResponseMessages.* resolved at runtime |
message: null | Passed through (no package fallback) | Package default message |
message: "" | Empty message | Empty message (preserved) |
NotFoundException without entity | new NotFoundException(BaseResponseCode.NotFound) | new NotFoundException() |
ConflictException without entity | new ConflictException(BaseResponseCode.Conflict) | new ConflictException() |
| Entity + custom message | new NotFoundException(entity, value, message: "…") | Supported (no errorCode required) |
BadRequestException single error | new BadRequestException(new[] { error }) | new BadRequestException(error) |
New constructors
| Type | New in v10.1.0 |
|---|---|
NotFoundException | NotFoundException() · NotFoundException(string entity, object value, string? message) |
ConflictException | ConflictException() · ConflictException(string entity, object value, string? message) |
BadRequestException | BadRequestException(ValidationError error) · BadRequestException(ValidationError error, int errorCode, string? message = null) |
| All exceptions | message 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
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.TooManyRequestsExceptionandServiceUnavailableException: New exception classes for HTTP 429 and 503.- Parameterless constructors:
ForbiddenException,UnauthorizedException,UnprocessableException,GatewayTimeoutException,TooManyRequestsException, andServiceUnavailableExceptionnow have parameterless constructors with sensible defaults. string messageconstructors: These exceptions now accept a singlestring messageparameter.initaccessors: All exception properties now use{ get; init; }for immutability after construction.
Full Changelog
See the package release notes for a complete version history.