Message Mapping + General Splitter: el error del wrapper que casi nadie ve venir
Caso real resuelto — un lote de oportunidades de venta que se divide, se transforma y se persiste en un Data Store. Incluye el error de runtime "Cannot produce target element" y cómo lo diagnostiqué con el trace.
Este es el primer caso de mi laboratorio que comparto completo, con capturas reales del tenant. El escenario: Logali Consulting recibe lotes de oportunidades ganadas desde un sistema de ventas (simulado con Postman) y debe convertir cada una en un borrador de producto, persistido en un Data Store para auditoría antes de sincronizar con S/4HANA.
Parece sencillo. Y lo es — hasta que el General Splitter te enseña algo que no está en la documentación.
La arquitectura
El iFlow IF_Logali_Product_Inbound_Batch (paquete Pkg_Logali_LeadToOrder) tiene 5 pasos:
- HTTPS Sender — recibe el lote XML en
/logali/products - General Splitter — divide el lote en una rama por oportunidad
- Content Modifier — captura el
ProductIdcon XPath - Message Mapping — transforma
Opportunity→ProductDraft - Write Data Store — persiste cada borrador con su ID como Entry ID
Paso a paso con evidencias
1. HTTPS Sender
Address /logali/products, autorización User Role con ESBMessaging.send y CSRF desactivado:
Canal HTTPS de entrada con autorización por rol.
2. General Splitter
XPath /Opportunities/Opportunity, Grouping 1 y Stop on Exception desactivado — si una oportunidad falla, las demás siguen procesándose:
El Splitter genera una rama por cada <Opportunity> del lote.
3. Content Modifier ANTES del mapping
Aquí va la primera lección: la property ProductId se captura con XPath antes de transformar el mensaje, porque después del mapping el body ya es un ProductDraft y el path /Opportunity/Id no existe:
La clave del Data Store se extrae mientras el XML todavía es una Opportunity.
4. Message Mapping
Y aquí viene el error del caso. Mi primer intento usaba Opportunity.xsd como source del mapping MM_SalesforceOpp_to_ProductDraft. El deploy pasó sin problemas… y el runtime explotó:
Cannot produce target element /ProductDraft
El monitor mostraba el mapping fallando en cada segmento del split.
¿La causa? Al inspeccionar Message before Step → Payload en el trace del primer segmento, descubrí que el General Splitter conserva el wrapper <Opportunities> en cada rama. El payload real no era:
<Opportunity>...</Opportunity>
sino:
<Opportunities>
<Opportunity>...</Opportunity>
</Opportunities>
El mapping esperaba un root Opportunity y recibía Opportunities. La solución definitiva (evalué normalizar el XML con un paso extra y lo descarté por innecesario):
- Source del mapping:
OpportunitiesSplit.xsd— un XSD que incluye el wrapper - Root mapping:
Opportunities → ProductDraft - Todos los campos desde
Opportunities/Opportunity/... - Y el XPath del Content Modifier también:
/Opportunities/Opportunity/Id
Source corregido: OpportunitiesSplit (con wrapper) → ProductDraft.
Los 7 campos mapeados, más la constante USD para el código de moneda:
Id→ProductId, Name→Name y Description, Amount→Price, Account/Id→SupplierId, Account/Name→SupplierName.
5. Write Data Store con parámetros externalizados
Entry ID ${property.ProductId} y Overwrite = Yes para garantizar idempotencia: reprocesar el mismo lote no genera duplicados.
Cada ProductDraft se persiste con su ProductId como clave.
El nombre del Data Store no va hardcodeado — se externaliza como {{dataStoreName}} y se configura en el deploy (DS_Logali_ProductDrafts), para que el transporte entre ambientes no requiera tocar el iFlow:
Externalized parameter: lo que cambia por ambiente nunca se hardcodea.
La prueba final
Lote de 3 oportunidades desde Postman → HTTP 200, y las 3 entradas en el Data Store con sus IDs correctos (OPP-2026-00042/43/44):
Happy path validado tras el fix.
Lecciones del caso
- El General Splitter conserva el wrapper. Antes de fijar el XSD source de un mapping post-split, revisa
Message before Step → Payloaden el trace del primer segmento. El payload real manda. - Captura las claves antes de transformar. Un Content Modifier mal ubicado (después del mapping) deja la property vacía sin lanzar ningún error.
- Externaliza lo que varía por ambiente. El nombre del Data Store funcionaba en DEV hardcodeado… y habría fallado el transporte.
- Nunca exportes credenciales reales. Las colecciones Postman van con variables
{{cpi_user}}/{{cpi_password}}marcadas como secret, y las capturas se sanitizan antes de compartir.
Este caso quedó documentado en mi knowledge base como el error CPI-014. En el próximo post: la versión preventiva de este mismo patrón.