# Troubleshooting healthcare interfaces

Every symptom a clinical interface shows, mapped to its cause and the page with the fix.

A clinical message passes through layers - the network, MLLP framing, routing, parsing, your service, its destinations - and a failure comes from one of them. This page maps what you observe to where it comes from.

## Start here {#start-here}

Before guessing at a cause, search [the audit log](https://zato.io/docs/dev/healthcare/audit-log.html) for the patient identifier or the MSH-10 control ID in question. Every message and its acknowledgment are recorded together as one exchange, so the search answers "did it arrive and was it acknowledged" first.

## Inbound - a system sending to you {#inbound-a-system-sending-to-you}

| Symptom | Layer | Where the fix is |
| --- | --- | --- |
| The sender cannot connect at all | The network - port 11553 (11554 for TLS) is not published or a firewall blocks the sender's address | [Connectivity and ports](https://zato.io/docs/dev/healthcare/hl7v2/mllp/index.html#ports-and-tls) |
| The feed is silent - no messages arrive, no errors either | The sender or the channel - connection open and close events appear in the server log per connection, so their absence means the sender never connects | [Logging](https://zato.io/docs/dev/healthcare/hl7v2/mllp/config.html#logging-and-errors) |
| The sender receives `AR` | Routing - no channel's rules match the message and there is no default channel, or your service raised an exception - the full error is in the server log and the audit log | [Routing](https://zato.io/docs/dev/healthcare/hl7v2/mllp/config.html#match-criteria) |
| The sender receives `AE` | Your service raised `HL7ApplicationError`, or validation rejected the message - the full error is in the server log and the audit log | [Acknowledgments](https://zato.io/docs/dev/healthcare/hl7v2/mllp/acknowledgments.html) |
| The sender receives `AE` or `AR` without error details | The channel's **Return errors** toggle is off, which is the production default - the details are on your side, in the logs | [Acknowledgments](https://zato.io/docs/dev/healthcare/hl7v2/mllp/acknowledgments.html) |
| The message was accepted (`AA`) but nothing happened downstream | Your service or its destinations - the audit log's flow view shows every event of that one message, across every system it touched | [Audit log views](https://zato.io/docs/admin/audit-log/views.html) |
| The same message was processed twice | Deduplication - the window is shorter than the sender's retransmission policy, is disabled, or the sender assigns a new MSH-10 on each retry | [Deduplication](https://zato.io/docs/dev/healthcare/hl7v2/mllp/config.html#deduplication) |
| The message fails to parse | The sender's formatting - tolerance repairs handle most non-compliant senders, and **Log messages** shows the payload before and after preprocessing | [Tolerance](https://zato.io/docs/dev/healthcare/hl7v2/mllp/config.html#tolerance-and-message-fixups) |
| Names or diacritics arrive garbled | Encoding - the sender's character set differs from what the channel decodes with, MSH-18 detection resolves most of it | [Encoding](https://zato.io/docs/dev/healthcare/hl7v2/mllp/config.html#protocol-options) |
| The connection closes with no ACK at all | Framing - the message exceeds the configured maximum size, so the connection is closed | [Protocol](https://zato.io/docs/dev/healthcare/hl7v2/mllp/config.html#protocol-options) |
| A batch (`FHS`/`BHS`) is rejected or parsed wrong | The channel parses batches as single messages - batch channels need **Parse on input** off | [Batch messages](https://zato.io/docs/dev/healthcare/hl7v2/mllp/index.html) |
| The sender insists a message was sent but you cannot find it | The audit log - it records every exchange, searchable by the MSH-10 control ID or a patient identifier | [Audit log views](https://zato.io/docs/admin/audit-log/views.html) |

## Outbound - you sending to other systems {#outbound-you-sending-to-other-systems}

| Symptom | Layer | Where the fix is |
| --- | --- | --- |
| `KeyError` on `self.mllp[name]` | The connection's name, or the connection is inactive | [Sending](https://zato.io/docs/dev/healthcare/hl7v2/mllp/outgoing.html) |
| An exception naming a timeout | The remote side answers slower than the connection's **Receive timeout** - 250 ms by default | [Sending](https://zato.io/docs/dev/healthcare/hl7v2/mllp/outgoing.html) |
| `is_accepted` is `False` with `AE` | The remote side failed to process the message - `error_text` contains what it reported | [Acknowledgments](https://zato.io/docs/dev/healthcare/hl7v2/mllp/acknowledgments.html) |
| `should_retry` is `True` | The remote side asked for a retry (`AR` or `CR`) - resubmitting the message as-is can work | [Resubmitting messages](https://zato.io/docs/admin/audit-log/resubmit.html) |
| A destination never acknowledges | The audit log's **Outstanding** filter lists the exchanges whose acknowledgment has not arrived, oldest first | [Audit log views](https://zato.io/docs/admin/audit-log/views.html) |
| One destination of several missed a message | A hop resend sends the stored payload to that one destination again, without touching the others | [Resubmitting messages](https://zato.io/docs/admin/audit-log/resubmit.html) |

## After an outage {#after-an-outage}

An interface that was down and is back up raises its own questions - what queued in the meantime, what to reprocess and what protects the catch-up from double-processing. [Downtime and recovery](https://zato.io/docs/dev/healthcare/downtime-and-recovery.html) covers that whole path.

## Where the details are {#where-the-details-are}

| Place | What it holds |
| --- | --- |
| The [audit log](https://zato.io/docs/admin/audit-log/index.html) | Every message with its acknowledgment, searchable by control ID and patient identifier, with the flow of each message across systems |
| `logs/server.log` | Connection events, routing decisions, framing warnings and service tracebacks |
| **Log messages** on a channel or connection | The full payloads, before and after tolerance preprocessing - development only, HL7 messages contain PHI |

## Learn more {#learn-more}

- [Healthcare interface engine](https://zato.io/docs/dev/healthcare/) - Clinical messages, FHIR, conversion and operations
- [HL7 v2 parsing](https://zato.io/docs/dev/healthcare/hl7/v2/parsing/) - Messages as typed objects, with field access and validation
- [MLLP channels](https://zato.io/docs/dev/healthcare/hl7v2/mllp/) - Receiving and sending HL7 v2 over MLLP sockets
- [FHIR integrations](https://zato.io/docs/dev/healthcare/hl7/fhir/) - Read and write FHIR resources, with paths, bundles and extensions
- [HL7 v2 to FHIR](https://zato.io/docs/dev/healthcare/hl7/to-fhir/) - Converting v2 messages into FHIR bundles, codes and references included
- [EDIFACT](https://zato.io/docs/dev/healthcare/edifact/) - Parsing interchanges, dialects and the transports they arrive on
- [Transformation](https://zato.io/docs/dev/healthcare/transformation/) - One message in, another standard out, in ordinary Python
- [Audit log](https://zato.io/docs/dev/healthcare/audit-log.html) - Every message with its acknowledgment, searchable by patient identifier
- [AI in clinical interfaces](https://zato.io/docs/dev/healthcare/ai/) - Services calling LLMs and AI agents calling clinical services as tools
