Message Mapping + General Splitter: the unexpected wrapper error
A solved real case — splitting a batch of sales opportunities, transforming each item and persisting it in a Data Store. Includes the runtime Cannot produce target element error and its Trace diagnosis.
This is the first complete laboratory case I am sharing, with real tenant screenshots. Logali Consulting receives batches of won opportunities from a sales system, simulated with Postman, and must convert each one into a product draft. The drafts are persisted in a Data Store for auditing before synchronization with S/4HANA.
It looks simple — until you inspect what the General Splitter actually produces.
Architecture
The iFlow IF_Logali_Product_Inbound_Batch, in package Pkg_Logali_LeadToOrder, has five steps:
- HTTPS Sender — receives the XML batch at
/logali/products. - General Splitter — splits it into one branch per opportunity.
- Content Modifier — captures
ProductIdusing XPath. - Message Mapping — transforms
Opportunity→ProductDraft. - Write Data Store — persists each draft using its ID as Entry ID.
Step by step with evidence
1. HTTPS Sender
Address /logali/products, User Role authorization with ESBMessaging.send, and CSRF disabled for this exercise:
Inbound HTTPS channel with role-based authorization.
2. General Splitter
XPath /Opportunities/Opportunity, Grouping 1, and Stop on Exception disabled so the remaining opportunities continue if one fails:
The Splitter creates one branch for each <Opportunity> in the batch.
3. Content Modifier BEFORE mapping
The first lesson: capture the ProductId property using XPath before transforming the message. After mapping, the body is a ProductDraft and the original opportunity path no longer exists:
Extract the Data Store key while the XML still contains an Opportunity.
4. Message Mapping
Here is the error in this case. My first attempt used Opportunity.xsd as the source for MM_SalesforceOpp_to_ProductDraft. Deployment succeeded, but runtime failed:
Cannot produce target element /ProductDraft
The monitor showed the mapping failing on each split segment.
Inspecting Message before Step → Payload in the first segment's Trace revealed that the General Splitter preserves the <Opportunities> wrapper. The actual payload was not:
<Opportunity>...</Opportunity>
It was:
<Opportunities>
<Opportunity>...</Opportunity>
</Opportunities>
The mapping expected root Opportunity but received Opportunities. I considered normalizing the XML in an extra step, then rejected that unnecessary addition. The final correction was:
- Mapping source:
OpportunitiesSplit.xsd, including the wrapper. - Root mapping:
Opportunities → ProductDraft. - All fields start at
Opportunities/Opportunity/.... - Content Modifier XPath:
/Opportunities/Opportunity/Id.
Corrected source: OpportunitiesSplit with its wrapper → ProductDraft.
Seven fields are mapped, plus constant USD for the currency code:
Id→ProductId, Name→Name and Description, Amount→Price, Account/Id→SupplierId, Account/Name→SupplierName.
5. Write Data Store with externalized parameters
Use Entry ID ${property.ProductId} and Overwrite = Yes for idempotency: reprocessing the same batch does not create duplicates.
Each ProductDraft is persisted using its ProductId as the key.
Externalize the Data Store name as {{dataStoreName}} and configure DS_Logali_ProductDrafts at deployment, so moving between environments does not require editing the iFlow:
Externalize values that change between environments.
Final test
A batch of three opportunities sent from Postman returned HTTP 200, with all three Data Store entries using their correct IDs (OPP-2026-00042/43/44):
Happy path validated after the fix.
Lessons
- The General Splitter preserves the wrapper in this configuration. Before choosing the source XSD for post-split mapping, inspect
Message before Step → Payloadin the first segment's Trace. The actual payload determines the contract. - Capture keys before transforming. Placing the Content Modifier after mapping can leave a property empty without throwing an error.
- Externalize environment-specific values. A hardcoded Data Store name may work in DEV but cause transport problems.
- Never export real credentials. Postman collections use
{{cpi_user}}/{{cpi_password}}secret variables, and screenshots are sanitized before sharing.
This case is documented as CPI-014 in my knowledge base. The next post presents the preventive version of the same pattern.