{"record":{"id":"22ac6ea3a6182881","repo":"apache/beam","slug":"error-fetching-hl7v2-message-with-id-writing-to-dead-letter","errorCode":null,"errorMessage":"Error fetching HL7v2 message with ID {} writing to Dead Letter Queue. ","messagePattern":"Error fetching HL7v2 message with ID (.+?) writing to Dead Letter Queue\\. ","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/HL7v2IO.java","lineNumber":576,"sourceCode":"    private final HealthcareApiClient client;\n\n    /** Instantiates a new HL7v2MessageClient (HCLS API v1). */\n    HL7v2MessageClient(HealthcareApiClient client) {\n      this.client = client;\n    }\n\n    private HL7v2Message fetchMessage(String msgId)\n        throws IOException, ParseException, IllegalArgumentException {\n      try {\n        com.google.api.services.healthcare.v1.model.Message msg = client.getHL7v2Message(msgId);\n        if (msg == null) {\n          throw new IOException(String.format(\"GET request for %s returned null\", msgId));\n        }\n        this.successfulHL7v2MessageGets.inc();\n        return HL7v2Message.fromModel(msg);\n      } catch (Exception e) {\n        failedMessageGets.inc();\n        LOG.warn(\n            \"Error fetching HL7v2 message with ID {} writing to Dead Letter Queue. \", msgId, e);\n        throw e;\n      }\n    }\n  }\n\n  /**\n   * List HL7v2 messages in HL7v2 Stores with optional filter.\n   *\n   * <p>This transform is optimized for splitting of message.list calls for large batches of\n   * historical data and assumes rather continuous stream of sendTimes.\n   *\n   * <p>Note on Benchmarking: The default initial splitting on day will make more queries than\n   * necessary when used with very small data sets (or very sparse data sets in the sendTime\n   * dimension). If you are looking to get an accurate benchmark be sure to use sufficient volume of\n   * data with messages that span sendTimes over a realistic time range (days)\n   *\n   * <p>Implementation includes overhead for:","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/HL7v2IO.java#L558-L594","documentation":"HL7v2IO's fetchMessage DoFn retrieves each HL7v2 message by ID from the Healthcare API. On any exception during the GET (null response, API error, network failure), failedMessageGets is incremented and this warning logged with the message ID and cause; the exception is then rethrown so the pipeline's failure handling (e.g. HealthcareIOError wrapping via HL7v2IO.Read's error handling) decides the outcome.","triggerScenarios":"Reading HL7v2IO.read().hl7V2Store(store) with message IDs that don't exist or were deleted; missing roles/healthcare.hl7V2MessageViewer permission; malformed store path; transient Healthcare API 5xx/timeout.","commonSituations":"Notifications from Pub/Sub referencing messages already purged; IAM changes mid-run; store name typos; quota exhaustion causing GET failures.","solutions":["Check the logged cause per msgId — 404 means the message was deleted/purged; 403 means IAM is missing.","Grant the service account roles/healthcare.hl7V2MessageViewer on the store/dataset.","Wrap the Read with error handling so failures go to a dead letter instead of failing the whole pipeline (HL7v2IO supports HealthcareIOError dead-letter on Read).","Verify the hl7v2Store path format and that Pub/Sub notification IDs are still retained by the store's message retention config."],"exampleFix":"// before\npipeline.apply(HL7v2IO.read().hl7V2Store(store)); // failures abort pipeline\n// after\nPCollection<HealthcareIOError<String>> dlq =\n    pipeline.apply(HL7v2IO.read().hl7V2Store(store)).get(HL7v2IO.Read.DEAD_LETTER);","handlingStrategy":"try-catch","validationCode":"// Java: validate store path before HL7v2IO.read()\nif (!store.matches(\"projects/[^/]+/locations/[^/]+/datasets/[^/]+/hl7V2Stores/[^/]+\")) {\n  throw new IllegalArgumentException(\"Invalid HL7v2 store: \" + store);\n}","typeGuard":null,"tryCatchPattern":"// Wrap per-message fetch and rethrow only after dead-lettering\ntry {\n  HL7v2Message msg = fetchMessage(msgId);\n} catch (java.io.IOException e) {\n  failedMessageGets.inc();\n  context.output(DEAD_LETTER, HealthcareIOError.of(msgId, e));\n  throw e;\n}","preventionTips":["Grant roles/healthcare.hl7V2MessageViewer to the pipeline service account.","Consume HL7v2IO.Read dead-letter output.","Check message retention so Pub/Sub-notified messages still exist at fetch time.","Retry transient 5xx before treating a fetch as permanent."],"tags":["gcp-healthcare","hl7v2","dead-letter","fetch-error"],"backgroundTag":"entity-not-found","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}