apache/beam · error · NoSuchElementException
Error listing FHIR resources from
Error message
Error listing FHIR resources from %s: %s
What it means
The FHIR resource listing page iterator in HttpHealthcareApiClient throws NoSuchElementException when fetching a subsequent page of FHIR search results raises IOException; pageToken is reset to null so iteration ends. The underlying API/network error text is appended after the store name.
Solutions
- Retry with backoff — transient network/5xx failures will abort iteration with this error
- Re-check IAM (roles/healthcare.fhirStoreViewer) if the embedded cause is 403
- Check the trailing %s for the concrete HTTP error (404 store deleted, 429 quota)
- Resume iteration from the last successful pageToken if the pipeline supports checkpointing
Example fix
// before
throw new NoSuchElementException(String.format("Error listing FHIR resources from %s: %s", fhirStore, e.getMessage()));
// after
// wrap iteration in retry
FluentBackoff backoff = FluentBackoff.DEFAULT.withMaxRetries(3).withInitialBackoff(Duration.standardSeconds(1));
try {
return BackOffUtils.next(sleeper, backoff.backoff(), () -> fetchPage(fhirStore));
} catch (IOException | InterruptedException e) {
throw new RuntimeException("FHIR listing failed for " + fhirStore, e);
} Defensive patterns
Strategy: retry
Validate before calling
java
if (pageToken != null && pageToken.isEmpty()) {
throw new IllegalArgumentException("Empty pageToken for FHIR listing");
} Try / catch
java
try {
resources = fetchNextPage(fhirStore);
} catch (NoSuchElementException e) {
// retry with exponential backoff; surface embedded cause after retries exhausted
throw new IOException("FHIR pagination failed: " + e.getMessage(), e);
} Prevention
- Wrap page fetches in retry with exponential backoff for 5xx/network blips
- Monitor rate limits on large FHIR stores
- Keep OAuth token refresh healthy in long-running pipelines
- Persist the last good pageToken for resumable reads
When it happens
Trigger: Second and later calls to the FHIR resource page iterator's next()/fetch when the FHIR search REST request fails: transient network errors, expired OAuth token, rate limiting, or the fhirStore becoming unavailable mid-iteration.
Common situations: Long-running Beam FHIR pipelines that lose connectivity mid-read; quota/rate-limit 429 responses on large FHIR stores; token refresh failures; concurrent deletion of the store.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Failed to list first page of FHIR resources from
- Error listing HL7v2 Messages from
- Failed to list first page of HL7v2 messages from
- 2xx codes should not be exceptions. Got status code
- Could not find earliest send time. The filter
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/53b0214a0baca7bf.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/HttpHealthcareApiClient.java:996
"Failed to list first page of FHIR resources from %s: %s",
fhirStore, e.getMessage()));
}
}
@Override
public JsonArray next() throws NoSuchElementException {
try {
HttpBody response = executeFhirRequest();
this.isFirstRequest = false;
JsonObject jsonResponse =
JsonParser.parseString(mapper.writeValueAsString(response)).getAsJsonObject();
JsonArray links = jsonResponse.getAsJsonArray("link");
this.pageToken = parsePageToken(links);
JsonArray resources = jsonResponse.getAsJsonArray("entry");
return resources;
} catch (IOException e) {
this.pageToken = null;
throw new NoSuchElementException(
String.format("Error listing FHIR resources from %s: %s", fhirStore, e.getMessage()));
}
}
private HttpBody executeFhirRequest() throws IOException {
switch (fhirMethod) {
case PATIENT_EVERYTHING:
return client.getPatientEverything(resourceName, parameters, pageToken);
case SEARCH:
default:
return client.searchFhirResource(fhirStore, resourceType, parameters, pageToken);
}
}
private static String parsePageToken(JsonArray links) throws MalformedURLException {
for (JsonElement e : links) {
JsonObject link = e.getAsJsonObject();
if (link.get("relation").getAsString().equalsIgnoreCase("next")) {View on GitHub (pinned to 12126d8942)