apereo/cas · info

Existing SOAP Envelope Body already contained children

Error message

Existing SOAP Envelope Body already contained children

What it means

CasHttpSoap11Encoder.buildAndStoreSOAPMessage() constructs a SOAP 1.1 Envelope with a single Body and stores the outgoing message. If the freshly built Body already contains unknown XMLObjects, it logs this warning before appending the payload, indicating leftover/pre-existing children in the Body that may yield an unexpected SOAP message structure. It is defensive logging rather than a hard failure.

Solutions

  1. Create a fresh CasHttpSoap11Encoder (and SOAP message context) per request instead of reusing instances
  2. Verify the payload is added exactly once and no earlier code populated the Body
  3. Inspect the produced SOAP envelope to confirm only the intended payload is present
  4. If the warning is benign in your flow, ensure the added payload ordering still satisfies the SAML binding spec

Example fix

// before: shared encoder field
private final CasHttpSoap11Encoder encoder = new CasHttpSoap11Encoder(...);
// after: per-use instance
val encoder = new CasHttpSoap11Encoder(builderFactory);
encoder.buildAndStoreSOAPMessage(payload);
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure a clean encoder/message per send
assert encoderNotReused && body.getUnknownXMLObjects().isEmpty();

Type guard

function bodyIsEmpty(body) { return body.getUnknownXMLObjects().isEmpty(); }

Try / catch

if (!body.getUnknownXMLObjects().isEmpty()) {
    log.warn('SOAP body pre-populated; constructing fresh envelope');
    encoder = newEncoder();
}

Prevention

When it happens

Trigger: Reusing an encoder or SOAP object tree where the Body element was previously populated (e.g. the encoder instance is reused across requests or the OpenSAML builder returns a cached/shared Body).

Common situations: Custom SAML SOAP encoding code reusing a single encoder instance for multiple messages; incorrectly wiring the OpenSAML builderFactory so it returns shared objects; embedding the encoder in a singleton Spring bean with state carried between calls.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/187db786ac15c07b. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-saml-core-api/src/main/java/org/apereo/cas/support/saml/util/CasHttpSoap11Encoder.java:45

    @Override
    protected void buildAndStoreSOAPMessage(
        @NonNull
        final XMLObject payload) {
        val builderFactory = XMLObjectProviderRegistrySupport.getBuilderFactory();

        val envBuilder =
            (SOAPObjectBuilder<Envelope>) builderFactory.getBuilder(Envelope.DEFAULT_ELEMENT_NAME);
        val envelope = envBuilder.buildObject(
            SOAPConstants.SOAP11_NS, Envelope.DEFAULT_ELEMENT_LOCAL_NAME, OPENSAML_11_SOAP_NS_PREFIX);

        val bodyBuilder =
            (SOAPObjectBuilder<Body>) builderFactory.getBuilder(Body.DEFAULT_ELEMENT_NAME);
        val body = bodyBuilder.buildObject(
            SOAPConstants.SOAP11_NS, Body.DEFAULT_ELEMENT_LOCAL_NAME, OPENSAML_11_SOAP_NS_PREFIX);

        if (!body.getUnknownXMLObjects().isEmpty()) {
            LOGGER.warn("Existing SOAP Envelope Body already contained children");
        }

        body.getUnknownXMLObjects().add(payload);
        envelope.setBody(body);
        this.storeSOAPEnvelope(envelope);
    }

}

View on GitHub (pinned to e7288fc434)