apache/beam · error

could not parse body from execute bundle response

Error message

could not parse body from execute bundle response

What it means

processResponseBody decodes the executeBundle response body as JSON into a struct with an 'entry' array. If the body is not valid JSON or has an incompatible shape, json.Decode fails and the error is wrapped with this message, the error counter is incremented, and the failure is emitted. This indicates the FHIR server returned something other than a well-formed Bundle response.

Solutions

  1. Log the raw response body on failure to see what was actually returned
  2. Verify the endpoint URL is a real FHIR store executeBundle endpoint
  3. Check for proxies/gateways injecting HTML error pages and bypass them
  4. Upgrade the Beam SDK — later fhirio versions harden body extraction and status checks
  5. Validate bundle size/timeouts so responses are not truncated mid-stream

Example fix

// before
err := json.NewDecoder(strings.NewReader(body)).Decode(&bodyFields)
if err != nil { emitFailure(errors.Wrap(err, "could not parse body...")) }
// after
if ct := response.Header.Get("Content-Type"); !strings.Contains(ct, "application/json") {
    emitFailure(fmt.Sprintf("unexpected content-type %q; body: %.200s", ct, body))
    return
}
err := json.NewDecoder(strings.NewReader(body)).Decode(&bodyFields)
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate the endpoint returns JSON before batch runs
resp, _ := http.Get(fhirStoreURL + "/metadata")
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") { return fmt.Errorf("endpoint not JSON: %s", ct) }

Try / catch

// decode defensively before handing to fhirio
var probe map[string]any
if err := json.Unmarshal([]byte(body), &probe); err != nil {
    return fmt.Errorf("non-JSON body from FHIR store: %w", err)
}

Prevention

When it happens

Trigger: json.NewDecoder(strings.NewReader(body)).Decode(&bodyFields) errors: the response body is empty, HTML (e.g. a proxy error page), truncated JSON, or otherwise not a FHIR Bundle object.

Common situations: A load balancer or auth proxy returning an HTML 502 page; sending requests to a non-FHIR endpoint; FHIR store returning an OperationOutcome with unexpected content-type that was not rejected earlier; body truncated by an interrupted connection.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/io/fhirio/execute_bundles.go:88

	if err != nil {
		fn.resourcesErrorCount.Inc(ctx, 1)
		emitFailure(errors.Wrap(err, "could not extract body from execute bundles response").Error())
		return
	}

	fn.processResponseBody(ctx, body, emitSuccess, emitFailure)
}

func (fn *executeBundleFn) processResponseBody(ctx context.Context, body string, emitSuccess, emitFailure func(string)) {
	var bodyFields struct {
		Type    string `json:"type"`
		Entries []any  `json:"entry"`
	}

	err := json.NewDecoder(strings.NewReader(body)).Decode(&bodyFields)
	if err != nil {
		fn.resourcesErrorCount.Inc(ctx, 1)
		emitFailure(errors.Wrap(err, "could not parse body from execute bundle response").Error())
		return
	}

	if bodyFields.Entries == nil {
		return
	}

	// A BATCH bundle returns a success response even if entries have failures, as
	// entries are executed separately. However, TRANSACTION bundles should return
	// error response (in client.executeBundle call) if any entry fails. Therefore,
	// for BATCH bundles we need to parse the error and success counters.
	switch bodyFields.Type {
	case bundleResponseTypeTransaction:
		fn.resourcesSuccessCount.Inc(ctx, int64(len(bodyFields.Entries)))
		emitSuccess(body)
	case bundleResponseTypeBatch:
		for _, entry := range bodyFields.Entries {
			var entryFields struct {

View on GitHub (pinned to 12126d8942)