{"record":{"id":"7169a77458585660","repo":"apache/beam","slug":"error-fetching-fhir-resource-with-id-writing-to-dead-letter","errorCode":null,"errorMessage":"Error fetching Fhir resource with ID {} writing to Dead Letter Queue. ","messagePattern":"Error fetching Fhir resource 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/FhirIO.java","lineNumber":612,"sourceCode":"        public void instantiateHealthcareClient() throws IOException {\n          this.client = new HttpHealthcareApiClient();\n          this.mapper = new ObjectMapper();\n        }\n\n        /**\n         * Process element.\n         *\n         * @param context the context\n         */\n        @ProcessElement\n        public void processElement(ProcessContext context) {\n          String resourceId = context.element();\n          String resource = null;\n          try {\n            resource = java.util.Objects.requireNonNull(fetchResource(this.client, resourceId));\n          } catch (Exception e) {\n            READ_RESOURCE_ERRORS.inc();\n            LOG.warn(\n                \"Error fetching Fhir resource with ID {} writing to Dead Letter Queue. \",\n                resourceId,\n                e);\n            context.output(FhirIO.Read.DEAD_LETTER, HealthcareIOError.of(resourceId, e));\n          }\n          if (resource != null) {\n            context.output(resource);\n          }\n        }\n\n        private String fetchResource(HealthcareApiClient client, String resourceName)\n            throws IOException, IllegalArgumentException {\n          long startTime = Instant.now().toEpochMilli();\n\n          HttpBody resource = client.readFhirResource(resourceName);\n          READ_RESOURCE_LATENCY_MS.update(Instant.now().toEpochMilli() - startTime);\n\n          if (resource == null) {","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/FhirIO.java#L594-L630","documentation":"FhirIO.Read (fhir_search/fetch by resource ID) fetches each FHIR resource by ID via the Healthcare API. If the fetch throws any exception (HTTP error, missing resource, auth failure, network error), the counter READ_RESOURCE_ERRORS is incremented, this warning is logged, and the failing resource ID is emitted to the DEAD_LETTER output as a HealthcareIOError instead of failing the pipeline.","triggerScenarios":"Calling FhirIO.read().fhirStore(store) with resource IDs that don't exist, have been deleted, are in a store the caller lacks fhir.resources.get permission on, or when the Healthcare API endpoint is unreachable/transiently failing.","commonSituations":"Downstream search results feeding stale IDs; pipeline credentials missing roles/healthcare.fhirResourceReader; store URL typos; resources deleted between search and fetch; transient 429/5xx from the API.","solutions":["Inspect the DEAD_LETTER PCollection (HealthcareIOError) for the failing IDs and the wrapped exception cause.","Grant the pipeline service account roles/healthcare.fhirResourceReader on the dataset/store.","Validate store paths (projects/{p}/locations/{l}/datasets/{d}/fhirStores/{s}) and resource ID formats before the read.","Retry transient failures; re-run the dead-lettered IDs in a follow-up job after fixing the cause."],"exampleFix":"// before (fail silently to DLQ, ignore)\n// after\nPCollection<HealthcareIOError<String>> dlq = result.get(FhirIO.Read.DEAD_LETTER);\ndlq.apply(ParDo.of(new LogAndAlertOnErrorDoFn()));","handlingStrategy":"try-catch","validationCode":"// Java: validate resource ID shape before Read\nif (!resourceId.matches(\"projects/[^/]+/locations/[^/]+/datasets/[^/]+/fhirStores/[^/]+/fhir/[A-Za-z]+/[^\"]+\")) {\n  throw new IllegalArgumentException(\"Invalid FHIR resource ID: \" + resourceId);\n}","typeGuard":null,"tryCatchPattern":"// Consume the dead letter output\nPCollection<HealthcareIOError<String>> dlq = fetched.get(FhirIO.Read.DEAD_LETTER);\ndlq.apply(ParDo.of(new DoFn<HealthcareIOError<String>, Void>() {\n  @ProcessElement\n  public void process(ProcessContext c) {\n    HealthcareIOError<String> err = c.element();\n    LOG.error(\"FHIR fetch failed for {}: {}\", err.getDataResource(), err.getErrorMessage());\n  }\n}));","preventionTips":["Always consume and monitor FhirIO.Read.DEAD_LETTER.","Grant roles/healthcare.fhirResourceReader to the pipeline service account.","Refresh IDs shortly before fetching to avoid stale/deleted resources.","Add retry for transient API errors upstream of the read."],"tags":["gcp-healthcare","fhir","dead-letter","fetch-error"],"backgroundTag":"api-request-failed","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"}