diff --git a/src/api/SIGCM2.Domain/Exceptions/AlicuotaInmutableException.cs b/src/api/SIGCM2.Domain/Exceptions/AlicuotaInmutableException.cs
new file mode 100644
index 0000000..24f159b
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/AlicuotaInmutableException.cs
@@ -0,0 +1,13 @@
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when a PATCH request attempts to change the Alicuota of an IngresosBrutos.
+/// Alicuota is immutable post-creation; use POST /iibb/{id}/nueva-version instead.
+///
+public sealed class AlicuotaInmutableException : DomainException
+{
+ public AlicuotaInmutableException()
+ : base("La alícuota de IngresosBrutos es inmutable. Creá una nueva versión vía POST /iibb/{id}/nueva-version.")
+ {
+ }
+}
diff --git a/src/api/SIGCM2.Domain/Exceptions/DuplicateCodigoException.cs b/src/api/SIGCM2.Domain/Exceptions/DuplicateCodigoException.cs
new file mode 100644
index 0000000..5b1beb5
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/DuplicateCodigoException.cs
@@ -0,0 +1,16 @@
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when a TipoDeIva with the same Codigo already exists for the same VigenciaDesde.
+/// Maps to SQL unique constraint UQ_TipoDeIva_Codigo_Vigencia (SqlException 2627/2601).
+///
+public sealed class DuplicateCodigoException : DomainException
+{
+ public string Codigo { get; }
+
+ public DuplicateCodigoException(string codigo)
+ : base($"Ya existe un TipoDeIva con Codigo '{codigo}' en la misma vigencia.")
+ {
+ Codigo = codigo;
+ }
+}
diff --git a/src/api/SIGCM2.Domain/Exceptions/DuplicateProvinciaException.cs b/src/api/SIGCM2.Domain/Exceptions/DuplicateProvinciaException.cs
new file mode 100644
index 0000000..84e9b12
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/DuplicateProvinciaException.cs
@@ -0,0 +1,18 @@
+using SIGCM2.Domain.Fiscal;
+
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when an IngresosBrutos entry for the same Provincia already exists for the same VigenciaDesde.
+/// Maps to SQL unique constraint UQ_IIBB_Provincia_Vigencia (SqlException 2627/2601).
+///
+public sealed class DuplicateProvinciaException : DomainException
+{
+ public ProvinciaArgentina Provincia { get; }
+
+ public DuplicateProvinciaException(ProvinciaArgentina provincia)
+ : base($"Ya existe una entrada de IIBB para '{provincia}' en la misma vigencia.")
+ {
+ Provincia = provincia;
+ }
+}
diff --git a/src/api/SIGCM2.Domain/Exceptions/PorcentajeInmutableException.cs b/src/api/SIGCM2.Domain/Exceptions/PorcentajeInmutableException.cs
new file mode 100644
index 0000000..3a0da31
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/PorcentajeInmutableException.cs
@@ -0,0 +1,13 @@
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when a PATCH request attempts to change the Porcentaje of a TipoDeIva.
+/// Porcentaje is immutable post-creation; use POST /iva/{id}/nueva-version instead.
+///
+public sealed class PorcentajeInmutableException : DomainException
+{
+ public PorcentajeInmutableException()
+ : base("El porcentaje de un TipoDeIva es inmutable. Creá una nueva versión vía POST /iva/{id}/nueva-version.")
+ {
+ }
+}
diff --git a/src/api/SIGCM2.Domain/Exceptions/PredecesorYaCerradoException.cs b/src/api/SIGCM2.Domain/Exceptions/PredecesorYaCerradoException.cs
new file mode 100644
index 0000000..4e45c70
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/PredecesorYaCerradoException.cs
@@ -0,0 +1,16 @@
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when attempting to create a new version from a predecessor that is already closed
+/// (VigenciaHasta is not null). The predecessor must be open to generate a new version.
+///
+public sealed class PredecesorYaCerradoException : DomainException
+{
+ public int PredecesorId { get; }
+
+ public PredecesorYaCerradoException(int predecesorId)
+ : base($"La versión {predecesorId} ya está cerrada o inactiva. No puede generar nueva versión.")
+ {
+ PredecesorId = predecesorId;
+ }
+}