diff --git a/src/api/SIGCM2.Domain/Exceptions/RubroEsRamaConHijosActivosException.cs b/src/api/SIGCM2.Domain/Exceptions/RubroEsRamaConHijosActivosException.cs
new file mode 100644
index 0000000..84bfda6
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/RubroEsRamaConHijosActivosException.cs
@@ -0,0 +1,19 @@
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when attempting to assign an aviso to a rubro that has active children.
+/// Invariante: un nodo con hijos activos es RAMA — no puede recibir avisos directos. → HTTP 409
+/// NOTE: no handler launches this in CAT-002. Consumer: PRD-002 CreateAvisoCommandHandler.
+///
+public sealed class RubroEsRamaConHijosActivosException : DomainException
+{
+ public int RubroId { get; }
+ public int CantidadHijos { get; }
+
+ public RubroEsRamaConHijosActivosException(int rubroId, int cantidadHijos)
+ : base($"El destino tiene sub-rubros. No puede contener avisos directos.")
+ {
+ RubroId = rubroId;
+ CantidadHijos = cantidadHijos;
+ }
+}
diff --git a/src/api/SIGCM2.Domain/Exceptions/RubroPadreEsHojaConAvisosException.cs b/src/api/SIGCM2.Domain/Exceptions/RubroPadreEsHojaConAvisosException.cs
new file mode 100644
index 0000000..143e785
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/RubroPadreEsHojaConAvisosException.cs
@@ -0,0 +1,18 @@
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when attempting to create or move a child into a rubro that already has avisos assigned.
+/// Invariante: un nodo con avisos es HOJA — no puede tener hijos. → HTTP 409
+///
+public sealed class RubroPadreEsHojaConAvisosException : DomainException
+{
+ public int ParentId { get; }
+ public int CantidadAvisos { get; }
+
+ public RubroPadreEsHojaConAvisosException(int parentId, int cantidadAvisos)
+ : base($"El rubro padre contiene {cantidadAvisos} avisos. Muévalos antes de crear sub-rubros.")
+ {
+ ParentId = parentId;
+ CantidadAvisos = cantidadAvisos;
+ }
+}
diff --git a/tests/SIGCM2.Application.Tests/Domain/Rubros/RubroReglaDeOroExceptionsTests.cs b/tests/SIGCM2.Application.Tests/Domain/Rubros/RubroReglaDeOroExceptionsTests.cs
new file mode 100644
index 0000000..6327d5b
--- /dev/null
+++ b/tests/SIGCM2.Application.Tests/Domain/Rubros/RubroReglaDeOroExceptionsTests.cs
@@ -0,0 +1,61 @@
+using FluentAssertions;
+using SIGCM2.Domain.Exceptions;
+
+namespace SIGCM2.Application.Tests.Domain.Rubros;
+
+public class RubroReglaDeOroExceptionsTests
+{
+ // ── RubroPadreEsHojaConAvisosException ──────────────────────────────────
+
+ [Fact]
+ public void RubroPadreEsHojaConAvisosException_Constructor_SetsMessage()
+ {
+ var ex = new RubroPadreEsHojaConAvisosException(parentId: 42, cantidadAvisos: 3);
+
+ ex.Message.Should().Be("El rubro padre contiene 3 avisos. Muévalos antes de crear sub-rubros.");
+ }
+
+ [Fact]
+ public void RubroPadreEsHojaConAvisosException_Constructor_SetsParentId_Y_CantidadAvisos()
+ {
+ var ex = new RubroPadreEsHojaConAvisosException(parentId: 42, cantidadAvisos: 3);
+
+ ex.ParentId.Should().Be(42);
+ ex.CantidadAvisos.Should().Be(3);
+ }
+
+ [Fact]
+ public void RubroPadreEsHojaConAvisosException_IsA_DomainException()
+ {
+ var ex = new RubroPadreEsHojaConAvisosException(parentId: 1, cantidadAvisos: 1);
+
+ ex.Should().BeAssignableTo();
+ }
+
+ // ── RubroEsRamaConHijosActivosException ─────────────────────────────────
+
+ [Fact]
+ public void RubroEsRamaConHijosActivosException_Constructor_SetsMessage()
+ {
+ var ex = new RubroEsRamaConHijosActivosException(rubroId: 7, cantidadHijos: 2);
+
+ ex.Message.Should().Be("El destino tiene sub-rubros. No puede contener avisos directos.");
+ }
+
+ [Fact]
+ public void RubroEsRamaConHijosActivosException_Constructor_SetsRubroId_Y_CantidadHijos()
+ {
+ var ex = new RubroEsRamaConHijosActivosException(rubroId: 7, cantidadHijos: 2);
+
+ ex.RubroId.Should().Be(7);
+ ex.CantidadHijos.Should().Be(2);
+ }
+
+ [Fact]
+ public void RubroEsRamaConHijosActivosException_IsA_DomainException()
+ {
+ var ex = new RubroEsRamaConHijosActivosException(rubroId: 1, cantidadHijos: 1);
+
+ ex.Should().BeAssignableTo();
+ }
+}