apache/beam · error · IllegalArgumentException

The PCollection tuple must have the FhirIO.Read.OUT and Fhir

Error message

The PCollection tuple must have the FhirIO.Read.OUT and FhirIO.Read.DEAD_LETTER tuple tags

What it means

FhirIO.Read.Result.of() requires the PCollectionTuple to contain both the FhirIO.Read.OUT and FhirIO.Read.DEAD_LETTER TupleTags, because a FHIR read produces successfully parsed resources on OUT and failures on DEAD_LETTER. If either tag is missing, the Result wrapper cannot function and an IllegalArgumentException is thrown immediately. This fail-fast check prevents later NullPointerExceptions when callers retrieve the output PCollections.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/FhirIO.java:480

      private PCollection<String> resources;

      private PCollection<HealthcareIOError<String>> failedReads;

      /** The Pct. */
      PCollectionTuple pct;

      /**
       * Create FhirIO.Read.Result form PCollectionTuple with OUT and DEAD_LETTER tags.
       *
       * @param pct the pct
       * @return the read result
       * @throws IllegalArgumentException the illegal argument exception
       */
      static FhirIO.Read.Result of(PCollectionTuple pct) throws IllegalArgumentException {
        if (pct.has(OUT) && pct.has(DEAD_LETTER)) {
          return new FhirIO.Read.Result(pct);
        } else {
          throw new IllegalArgumentException(
              "The PCollection tuple must have the FhirIO.Read.OUT "
                  + "and FhirIO.Read.DEAD_LETTER tuple tags");
        }
      }

      private Result(PCollectionTuple pct) {
        this.pct = pct;
        this.resources = pct.get(OUT);
        this.failedReads =
            pct.get(DEAD_LETTER).setCoder(HealthcareIOErrorCoder.of(StringUtf8Coder.of()));
      }

      /**
       * Gets failed reads.
       *
       * @return the failed reads
       */
      public PCollection<HealthcareIOError<String>> getFailedReads() {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Apply both tags to the tuple: pct.apply(FhirIO.Read.OUT, resources) and pct.apply(FhirIO.Read.DEAD_LETTER, failures) before Result.of(pct)
  2. Use the FhirIO.Read transform's returned Result directly instead of rebuilding a PCollectionTuple
  3. Reference the exact constants FhirIO.Read.OUT and FhirIO.Read.DEAD_LETTER when populating the tuple
  4. Guard the call with pct.has(OUT) && pct.has(DEAD_LETTER) during development

Example fix

// before
PCollectionTuple pct = PCollectionTuple.of(FhirIO.Read.OUT, resources);
FhirIO.Read.Result r = FhirIO.Read.Result.of(pct); // throws
// after
PCollectionTuple pct = new PCollectionTuple(pipeline);
pct.put(FhirIO.Read.OUT, resources);
pct.put(FhirIO.Read.DEAD_LETTER, failures);
FhirIO.Read.Result r = FhirIO.Read.Result.of(pct);
Defensive patterns

Strategy: validation

Validate before calling

if (pct.has(FhirIO.Read.OUT) && pct.has(FhirIO.Read.DEAD_LETTER)) {
  FhirIO.Read.Result r = FhirIO.Read.Result.of(pct);
}

Try / catch

try {
  FhirIO.Read.Result r = FhirIO.Read.Result.of(pct);
} catch (IllegalArgumentException e) {
  LOG.error("Tuple missing FhirIO.Read.OUT/DEAD_LETTER tags", e);
}

Prevention

When it happens

Trigger: Calling FhirIO.Read.Result.of(pct) with a PCollectionTuple that lacks either the OUT or DEAD_LETTER tag — e.g. a tuple assembled from a custom transform that only emits the OUT collection.

Common situations: Manually constructing the PCollectionTuple instead of using the return value of the FhirIO.Read transform; renaming or re-declaring TupleTags so the contains check fails; adapting code from another IO connector whose Result.of only needed one tag.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/654a012d679cf1a7. Report an issue: GitHub.