{"record":{"id":"563367cea2e90b48","repo":"apache/beam","slug":"the-pcollection-tuple-must-have-the-fhirio-search-out-and","errorCode":null,"errorMessage":"The PCollection tuple must have the FhirIO.Search.OUT and FhirIO.Search.DEAD_LETTER tuple tags","messagePattern":"The PCollection tuple must have the FhirIO\\.Search\\.OUT and FhirIO\\.Search\\.DEAD_LETTER tuple tags","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/FhirIO.java","lineNumber":1859,"sourceCode":"\n      private final PCollection<KV<String, JsonArray>> keyedResources;\n      private final PCollection<JsonArray> resources;\n\n      private final PCollection<HealthcareIOError<String>> failedSearches;\n      PCollectionTuple pct;\n\n      /**\n       * Create FhirIO.Search.Result form PCollectionTuple with OUT and DEAD_LETTER tags.\n       *\n       * @param pct the pct\n       * @return the search result\n       * @throws IllegalArgumentException the illegal argument exception\n       */\n      static FhirIO.Search.Result of(PCollectionTuple pct) throws IllegalArgumentException {\n        if (pct.has(OUT) && pct.has(DEAD_LETTER)) {\n          return new FhirIO.Search.Result(pct);\n        } else {\n          throw new IllegalArgumentException(\n              \"The PCollection tuple must have the FhirIO.Search.OUT \"\n                  + \"and FhirIO.Search.DEAD_LETTER tuple tags\");\n        }\n      }\n\n      private Result(PCollectionTuple pct) {\n        this.pct = pct;\n        this.keyedResources =\n            pct.get(OUT).setCoder(KvCoder.of(StringUtf8Coder.of(), JsonArrayCoder.of()));\n        this.resources =\n            this.keyedResources\n                .apply(\n                    \"Extract Values\",\n                    MapElements.into(TypeDescriptor.of(JsonArray.class)).via(KV::getValue))\n                .setCoder(JsonArrayCoder.of());\n        this.failedSearches =\n            pct.get(DEAD_LETTER).setCoder(HealthcareIOErrorCoder.of(StringUtf8Coder.of()));\n      }","sourceCodeStart":1841,"sourceCodeEnd":1877,"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#L1841-L1877","documentation":"FhirIO.Search.Result.of() requires the PCollectionTuple to contain both the FhirIO.Search.OUT and FhirIO.Search.DEAD_LETTER TupleTags, since FHIR search output is split into successful responses (OUT) and failed searches (DEAD_LETTER). If either tag is absent the Result wrapper cannot be constructed and an IllegalArgumentException is thrown. This is a pipeline-construction-time fail-fast check mirroring the other healthcare IO Result.of methods.","triggerScenarios":"Calling FhirIO.Search.Result.of(pct) on a PCollectionTuple missing OUT or DEAD_LETTER — e.g. manually building a tuple with only the OUT collection, or using different TupleTag instances than the FhirIO.Search constants.","commonSituations":"Copy-pasting tuple wiring from another connector with different tag constants; renaming tags during refactor; constructing the Result without running the FhirIO.Search transform first.","solutions":["Apply both tags before calling of(): pct.apply(FhirIO.Search.OUT, results) and pct.apply(FhirIO.Search.DEAD_LETTER, deadLetters)","Use the exact constants FhirIO.Search.OUT and FhirIO.Search.DEAD_LETTER, not locally created TupleTags","Prefer consuming the Result returned by the FhirIO.Search transform instead of hand-building the tuple","Add pct.has(OUT) && pct.has(DEAD_LETTER) as a pre-check during development"],"exampleFix":"// before\nPCollectionTuple pct = PCollectionTuple.of(FhirIO.Search.OUT, searchResults);\nFhirIO.Search.Result r = FhirIO.Search.Result.of(pct); // throws\n// after\npct.put(FhirIO.Search.DEAD_LETTER, failedSearches);\nFhirIO.Search.Result r = FhirIO.Search.Result.of(pct);","handlingStrategy":"validation","validationCode":"if (pct.has(FhirIO.Search.OUT) && pct.has(FhirIO.Search.DEAD_LETTER)) {\n  FhirIO.Search.Result r = FhirIO.Search.Result.of(pct);\n}","typeGuard":null,"tryCatchPattern":"try {\n  FhirIO.Search.Result r = FhirIO.Search.Result.of(pct);\n} catch (IllegalArgumentException e) {\n  LOG.error(\"Tuple missing FhirIO.Search.OUT/DEAD_LETTER tags\", e);\n}","preventionTips":["Wire both OUT and DEAD_LETTER tags using the library constants","Consume the transform's returned Result instead of rebuilding the tuple","Add a pipeline-construction test covering FhirIO.Search wiring"],"tags":["java","fhir","search","healthcare","pcollection-tuple"],"backgroundTag":"missing-required-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}