HL7Exception: Can't find ZRT as a direct child when using custom segment

17 views
Skip to first unread message

Shreeja J

unread,
Oct 11, 2025, 9:20:08 AM (6 days ago) Oct 11
to HAPI FHIR

Hello HAPI Team,

I am encountering an issue while parsing HL7 messages with a custom segment (ZRT) .I am using:

  • Java 21

  • Spring Boot 3.3.3

  • GenericParser from HAPI HL7 v2

  • Supporting HL7 versions v23 through v28

When I try to access the custom segment using Terser, I get the following exception:

```

ca.uhn.hl7v2.HL7Exception: Can't find ZRT as a direct child
    at ca.uhn.hl7v2.util.SegmentFinder.getStructure(SegmentFinder.java:141)
    at ca.uhn.hl7v2.util.SegmentFinder.getSegment(SegmentFinder.java:108)
    at ca.uhn.hl7v2.util.Terser.getSegment(Terser.java:358)
    at ca.uhn.hl7v2.util.Terser.get(Terser.java:324)
    at org.techbd.ingest.service.ZrtSegmentParserTest.assertZrtFields(ZrtSegmentParserTest.java:63)
    at org.techbd.ingest.service.ZrtSegmentParserTest.testCustomSegmentAfterPID(ZrtSegmentParserTest.java:49)
```

  I am including the full JUnit test file for reference.

```
package org.service;

import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.parser.GenericParser;
import ca.uhn.hl7v2.util.Terser;
import ca.uhn.hl7v2.validation.impl.NoValidation;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class ZrtSegmentParserTest {

    private final GenericParser parser;

    public ZrtSegmentParserTest() {
        parser = new GenericParser();
        parser.setValidationContext(new NoValidation()); // Disable HL7 validation
    }

    // ---------------------------
    // Sample HL7 Messages
    // ---------------------------

    private static final String HL7_PUSH =
            "MSH|^~\\&||DUMMYHOSP|||||ORU^R01|||2.5\r" +
            "PID||123456^^^DUMMY:FACID^MRN|123456^^^DUMMY:FACID^MRN||Doe^John^A||19800101|M\r" +
            "ZRT||ORU|R01|PUSH|||||123456^dummy:ABC~654321^dummy:XYZ|abcdef123456|userId^Test^User|add";

    private static final String HL7_PBRD_ZRT_AFTER_MSH =
            "MSH|^~\\&||DUMMYHOSP|||||ORU^R01|||2.5\r" +
            "ZRT||ORU|R01|PBRD|||A1^DOE^JANE^ABC^ATT~B2^DOE^JANE^XYZ^CON|dummy:FAC|987654^dummy:ABC~456789^dummy:XYZ|abcdef987654||\r" +
            "PID||123456^^^DUMMY:FACID^MRN|123456^^^DUMMY:FACID^MRN||Doe^John^A||19800101|M";

    // ---------------------------
    // Tests
    // ---------------------------

    @Test
    @DisplayName("Test ZRT segment after MSH")
    void testCustomSegmentAfterMSH() throws HL7Exception {
        assertZrtFields(HL7_PBRD_ZRT_AFTER_MSH, "PBRD", "dummy:FAC", "ORU");
    }

    @Test
    @DisplayName("Test ZRT segment after PID")
    void testCustomSegmentAfterPID() throws HL7Exception {
        assertZrtFields(HL7_PUSH, "PUSH", "dummy:ABC", "ORU");
    }

    // ---------------------------
    // Helper Method
    // ---------------------------

    private void assertZrtFields(String hl7Message, String expectedDeliveryType,
                                 String expectedFacility, String expectedMessageCode) throws HL7Exception {

        Message message = parser.parse(hl7Message);

        Terser terser = new Terser(message);

        String messageCode = terser.get("/ZRT-2");
        String triggerEvent = terser.get("/ZRT-3");
        String deliveryType = terser.get("/ZRT-4");
        String facility = terser.get("/ZRT-8");

        assertThat(messageCode).isEqualTo(expectedMessageCode);
        assertThat(triggerEvent).isNotEmpty();
        assertThat(deliveryType).isEqualTo(expectedDeliveryType);
        assertThat(facility).isEqualTo(expectedFacility);

        System.out.printf("ZRT parsed: %s | %s | %s | %s%n",
                messageCode, triggerEvent, deliveryType, facility);
    }
}
```  

Dependencies Used:

```
<dependency>
    <groupId>ca.uhn.hapi</groupId>
    <artifactId>hapi-base</artifactId>
    <version>${hapi.version}</version>
</dependency>
<dependency>
    <groupId>ca.uhn.hapi</groupId>
    <artifactId>hapi-structures-v23</artifactId>
    <version>${hapi.version}</version>
</dependency>
<dependency>
    <groupId>ca.uhn.hapi</groupId>
    <artifactId>hapi-structures-v24</artifactId>
    <version>${hapi.version}</version>
</dependency>
<dependency>
    <groupId>ca.uhn.hapi</groupId>
    <artifactId>hapi-structures-v25</artifactId>
    <version>${hapi.version}</version>
</dependency>
<dependency>
    <groupId>ca.uhn.hapi</groupId>
    <artifactId>hapi-structures-v26</artifactId>
    <version>${hapi.version}</version>
</dependency>
<dependency>
    <groupId>ca.uhn.hapi</groupId>
    <artifactId>hapi-structures-v27</artifactId>
    <version>${hapi.version}</version>
</dependency>
<dependency>
    <groupId>ca.uhn.hapi</groupId>
    <artifactId>hapi-structures-v28</artifactId>
    <version>${hapi.version}</version>
</dependency>
```

Question:
  How can I correctly parse a custom segment like ZRT using Terser when it may appear anywhere in the message (not necessarily after MSH)? Is there a recommended way to register custom segments so they can be reliably accessed, regardless of their position?  

Thank you for your guidance!

Shreeja

Reply all
Reply to author
Forward
0 new messages