diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java
index 9f392a2c4..c6f4232e2 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java
@@ -1188,4 +1188,5 @@ public class I18nConstants {
   public static final String VALIDATION_AI_TEXT_CODE = "VALIDATION_AI_TEXT_CODE";
   public static final String VALIDATION_AI_FAILED = "VALIDATION_AI_FAILED";
   public static final String VALIDATION_AI_FAILED_LOG = "VALIDATION_AI_FAILED_LOG";
+  public static final String RESOURCE_DUPLICATE_CONTAINED_ID = "RESOURCE_DUPLICATE_CONTAINED_ID";
 }
diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties
index 52544803d..e11b78f39 100644
--- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties
+++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties
@@ -1219,4 +1219,5 @@ REFERENCE_RESOLUTION_FAILED = Fetching ''{0}'' failed. System details: {1}: {2}
 VALIDATION_AI_TEXT_CODE = Apparent mis-match between code ''{0}'' and text ''{1}'': {3} ({2} confidence)
 VALIDATION_AI_FAILED = Consulting AI failed: {0}
 VALIDATION_AI_FAILED_LOG = Consulting AI failed: {0} (see {1} for further details)
+RESOURCE_DUPLICATE_CONTAINED_ID = Duplicate ID for contained resource: {0}
 
diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java
index f5e0f85cb..5800f185b 100644
--- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java
+++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java
@@ -6375,6 +6375,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
             hc = valContext.forContained(element);
           }
 
+          if (special == SpecialElement.CONTAINED) {
+            String id = element.getNamedChildValue("id");
+            if (id == null) {
+              // this is an error handled elsewhere
+            } else {
+              ok = rule(errors, "2025-01-28", IssueType.DUPLICATE, element.line(), element.col(), stack.getLiteralPath(),
+                  !stack.getIds().containsKey("!"+id), I18nConstants.RESOURCE_DUPLICATE_CONTAINED_ID, id) && ok;
+              stack.getIds().put("!"+id, element);
+            }
+          }
           stack.resetIds();
           if (special != null) {
             switch (special) {