Input & Output
The real node data envelope, how DataMapping reads its input, output ports, and the exact output shape.
The Node Data Envelope
Every node's input and output — not just DataMapping's — is a JSON object shaped like this. The top-level fields are run metadata; the real payload lives under items, one entry per record, each holding the record under "json":
{
"timestamp": "2026-07-24T01:02:27.8652562Z",
"triggerTime": "2026-07-24T01:02:27.8652562Z",
"resource": "trigger",
"operation": "manual-trigger",
"status": "success",
"portName": "main",
"items": [
{
"json": {
"timestamp": "2026-07-24T01:02:27.8652562Z",
"triggerTime": "2026-07-24T01:02:27.8652562Z",
"resource": "trigger",
"operation": "manual-trigger",
"status": "success",
"portName": "main"
}
}
],
"success": true
}
DataMapping's real input is InputData["items"] — it unwraps each entry's "json" value and treats that as one source record. It never reads the outer envelope fields (timestamp, resource, operation, status, portName, success) as mapping input; those describe the upstream node's run, not your data.
When you manually type test data into inlineDataSource, or when some other node freshly fetches data from an external API and you want to test a mapping against a sample of it, that raw JSON does not need to already look like the envelope above. A single object like { "orderId": "ORD-1", "total": 129.5 }, or a plain array of such objects, is exactly right. DataMapping (via the shared ResolveSourceRecords helper) parses whatever you typed and normalizes it into the standard items/json shape itself before producing output — you never hand-author the envelope.
Output Ports
| Port | Condition | Description |
|---|---|---|
| success | Mapping (or passthrough) completed | Every mapped record is available downstream via output.NodeName.items[].json. |
| error | dataMappings is empty (outside passthrough mode), the source could not be resolved at all, or an unhandled exception occurs | Error details in output.NodeName.error, plus a "data mapping failed" activity log entry. |
The numeric/date transforms (toint, todecimal, toboolean, tofloat/todouble, todate/todatetime) and the expression transform never throw — a failed conversion or expression error silently returns the original, untransformed value in place. A missing source field similarly just resolves to null. None of these route to error; only an empty dataMappings array (outside passthrough mode), a fully unresolvable source, or a genuinely unhandled exception does.
Output Data Schema
| Field | Type | Description |
|---|---|---|
status | string | Literal "success" on the success path. |
mappingFieldCount | integer | The count of mapping rules that were applied to each record. In passthrough mode this is still the rule count (typically 0 if none were configured). |
recordCount | integer | How many records were resolved and mapped. Matches the number of entries in items. |
items | array | The framework's standard [{ "json": <record> }, ...] item shape — one entry per record. json holds the mapped record (a flat { targetField: value, ... } dictionary), or in passthrough mode, the resolved source record unchanged. Merged against any pre-existing items per OutputItemMergeType (default: full replace). |
Example: Upstream Input Through to Mapped Output
Upstream input — an HTTP Request node's output, feeding DataMapping's default InputData["items"] read:
{
"timestamp": "2026-07-24T08:15:02.1200000Z",
"triggerTime": "2026-07-24T08:15:00.0000000Z",
"resource": "http-request",
"operation": "GET",
"status": "success",
"portName": "main",
"items": [
{
"json": {
"contact": {
"fullName": " Jane Doe ",
"emailAddress": "[email protected]",
"phone": "(512) 555-1234",
"createdAt": "2023-11-15T00:00:00Z",
"accountBalance": 1234.5,
"firstName": "Jane",
"lastName": "Doe"
}
}
}
],
"success": true
}
DataMapping configuration:
{
"dataMappings": [
{ "sourceField": "contact.fullName", "targetField": "displayName", "transform": "trim" },
{ "sourceField": "contact.emailAddress", "targetField": "email", "transform": "lowercase" },
{ "sourceField": "contact.phone", "targetField": "phoneE164", "transform": "regexreplace:[^0-9]:" },
{ "sourceField": "contact.createdAt", "targetField": "memberSince", "transform": "todate" },
{ "sourceField": "contact.accountBalance","targetField": "balance", "transform": "todecimal" },
{ "sourceField": "contact.firstName", "targetField": "fullName", "transform": "expression", "transformExpression": "item.contact.firstName + ' ' + item.contact.lastName" }
]
}
Output after Data Mapping runs with the configuration above (note: this node's own output is always wrapped in the same envelope shape shown at the top of this page — status/recordCount/mappingFieldCount alongside items):
{
"status": "success",
"mappingFieldCount": 6,
"recordCount": 1,
"items": [
{
"json": {
"displayName": "Jane Doe",
"email": "[email protected]",
"phoneE164": "5125551234",
"memberSince": "2023-11-15T00:00:00Z",
"balance": 1234.5,
"fullName": "Jane Doe"
}
}
]
}
Multiple Upstream Records In → Multiple Output Items
When the upstream items array holds many records (e.g. a database-query node's result set), DataMapping maps each independently and produces one output item per input record — never one item wrapping the whole array:
// Upstream input.items (2 records, e.g. from a SQL query node):
[
{ "json": { "contact": { "fullName": "Alice Wong", "emailAddress": "[email protected]" } } },
{ "json": { "contact": { "fullName": "Marcus Reed", "emailAddress": "[email protected]" } } }
]
// DataMapping output.items (2 mapped records, recordCount: 2):
[
{ "json": { "displayName": "Alice Wong", "email": "[email protected]" } },
{ "json": { "displayName": "Marcus Reed", "email": "[email protected]" } }
]
Passthrough Mode Output
With dataMappingMode: "passthrough" and the same upstream input, each item's json is the resolved source record unchanged:
{
"status": "success",
"mappingFieldCount": 0,
"recordCount": 1,
"items": [
{
"json": {
"contact": {
"fullName": " Jane Doe ",
"emailAddress": "[email protected]",
"phone": "(512) 555-1234",
"createdAt": "2023-11-15T00:00:00Z",
"accountBalance": 1234.5,
"firstName": "Jane",
"lastName": "Doe"
}
}
}
]
}
Using inlineDataSource Instead of Upstream Input
Type plain JSON — no envelope needed — directly into inlineDataSource:
// inlineDataSource (exactly what you type in the designer):
{ "orderId": "ORD-7741", "total": 129.50, "customerEmail": "[email protected]" }
// DataMapping configuration:
{
"inlineDataSource": "{ \"orderId\": \"ORD-7741\", \"total\": 129.50, \"customerEmail\": \"[email protected]\" }",
"dataMappings": [
{ "sourceField": "orderId", "targetField": "id" },
{ "sourceField": "total", "targetField": "amount", "transform": "todecimal" },
{ "sourceField": "customerEmail", "targetField": "email", "transform": "lowercase" }
]
}
// Output — normalized into the standard envelope automatically:
{
"status": "success",
"mappingFieldCount": 3,
"recordCount": 1,
"items": [
{ "json": { "id": "ORD-7741", "amount": 129.5, "email": "[email protected]" } }
]
}
Accessing Output Downstream
| Expression | Result |
|---|---|
{@ output.NormaliseContact.items[0].json } | The entire first mapped record object |
{@ output.NormaliseContact.items[0].json.email } | "[email protected]" |
{@ output.NormaliseContact.items[0].json.balance } | 1234.5 |
{@ output.NormaliseContact.mappingFieldCount } | 6 |
{@ output.NormaliseContact.recordCount } | 1 (or however many records were mapped — pair with a Loop node when greater than one) |
{@ output.NormaliseContact.status } | "success" |
Error Output
When no mapping rules are configured (outside passthrough mode), the source cannot be resolved at all, or an unhandled exception occurs, the node logs a "data mapping failed" activity entry and routes to the configured error port instead of populating items.