Zie619/n8n-workflows · error · Error
No EDI message found in input. Please provide the EDI messag
Error message
No EDI message found in input. Please provide the EDI message in the "ediMessage" property.
What it means
Thrown by 'Parse EDI Message' (workflow 0793). After parsing the EDIFACT message it reads const ediMessage = $input.first().json.body and throws this message when body is falsy. Note the mismatch: the message tells the user to supply an 'ediMessage' property, but the code actually reads .body — following the error text and providing ediMessage will not fix it.
Source
Thrown at workflows/Splitout/0793_Splitout_Code_Send_Triggered.json:1332
"simple": false,
"options": {},
"messageId": "={{ $json.id }}",
"operation": "get"
},
"notesInFlow": true,
"typeVersion": 2.1,
"notes": "This gmail node performs automated tasks as part of the workflow."
},
{
"id": "0346eabe-552a-47d8-ac9e-9619926d0242",
"name": "Parse EDI Message",
"type": "n8n-nodes-base.code",
"position": [
-4660,
-860
],
"parameters": {
"jsCode": "// EDI Parser function for n8n JavaScript node\nfunction parseEDI(ediMessage) {\n // Define the data structure to store parsed results\n const result = {\n interchangeHeader: {},\n messageHeader: {},\n orderDetails: {},\n dates: [],\n parties: [],\n lineItems: []\n };\n \n // Split the message into lines and remove empty lines\n const lines = ediMessage.split(\"'\").filter(line => line.trim().length > 0);\n \n // Parse each line\n let currentLineItem = null;\n \n for (const line of lines) {\n const segments = line.trim().split('+');\n const segmentName = segments[0];\n \n switch (segmentName) {\n case 'UNA':\n // Service String Advice - contains delimiter information\n break;\n \n case 'UNB':\n // Interchange Header\n // UNB+UNOC:3+SENDER_ID+RECEIVER_ID+240318:1200+ORDER54321\n result.interchangeHeader = {\n syntax: segments[1],\n senderId: segments[2],\n receiverId: segments[3],\n dateTime: segments[4]?.split(':')[0] || '',\n time: segments[4]?.split(':')[1] || '',\n controlReference: segments[5] || ''\n };\n break;\n \n case 'UNH':\n // Message Header\n // UNH+1+ORDERS:D:96A:UN\n if (segments.length > 2) {\n const messageParts = segments[2].split(':');\n result.messageHeader = {\n messageReference: segments[1],\n messageType: messageParts[0],\n messageVersion: messageParts[1],\n messageRelease: messageParts[2],\n controlAgency: messageParts[3]\n };\n }\n break;\n \n case 'BGM':\n // Beginning of Message\n // BGM+230+RT54321098+9\n result.orderDetails = {\n documentType: segments[1],\n documentNumber: segments[2],\n messageFunction: segments[3]\n };\n break;\n \n case 'DTM':\n // Date/Time/Period\n // DTM+137:20250319:102\n if (segments[1]) {\n const dateParts = segments[1].split(':');\n const dateObj = {\n qualifier: dateParts[0],\n date: dateParts[1],\n format: dateParts[2]\n };\n \n // Add human-readable description based on qualifier\n switch (dateParts[0]) {\n case '137':\n dateObj.description = 'Document Date';\n break;\n case '2':\n dateObj.description = 'Delivery Date';\n break;\n case '10':\n dateObj.description = 'Shipment Date';\n break;\n default:\n dateObj.description = 'Other Date';\n }\n \n result.dates.push(dateObj);\n }\n break;\n \n case 'NAD':\n // Name and Address\n // NAD+BY+CUSTOMER_123::91\n if (segments.length > 1) {\n const partyCode = segments[1];\n const partyId = segments[2]?.split(':')[0] || '';\n \n const party = {\n partyQualifier: partyCode,\n partyId: partyId,\n qualifierDescription: ''\n };\n \n // Add human-readable description\n switch (partyCode) {\n case 'BY':\n party.qualifierDescription = 'Buyer';\n break;\n case 'SU':\n party.qualifierDescription = 'Supplier';\n break;\n case 'DP':\n party.qualifierDescription = 'Delivery Party';\n break;\n default:\n party.qualifierDescription = 'Other Party';\n }\n \n // If there's a full name instead of a code (like \"Returns Processing Hub\")\n if (segments[2] && !segments[2].includes(':')) {\n party.partyName = segments[2];\n party.partyId = '';\n }\n \n result.parties.push(party);\n }\n break;\n \n case 'LIN':\n // Line Item\n // LIN+1++321654:IN\n currentLineItem = {\n lineNumber: segments[1],\n productId: '',\n productIdType: '',\n description: '',\n quantity: 0,\n unit: '',\n price: 0\n };\n \n // Parse product ID if present\n if (segments[3]) {\n const productParts = segments[3].split(':');\n currentLineItem.productId = productParts[0];\n currentLineItem.productIdType = productParts[1] || '';\n }\n \n result.lineItems.push(currentLineItem);\n break;\n \n case 'IMD':\n // Item Description\n // IMD+F++:::Defective Product A\n if (currentLineItem && segments.length > 3) {\n // The description is typically in the last component after multiple colons\n const descriptionParts = segments[3].split(':');\n currentLineItem.description = descriptionParts[descriptionParts.length - 1];\n }\n break;\n \n case 'QTY':\n // Quantity\n // QTY+21:10:EA\n if (currentLineItem && segments[1]) {\n const quantityParts = segments[1].split(':');\n currentLineItem.quantityQualifier = quantityParts[0];\n currentLineItem.quantity = parseFloat(quantityParts[1] || '0');\n currentLineItem.unit = quantityParts[2] || '';\n }\n break;\n \n case 'PRI':\n // Price Details\n // PRI+AAA:0.00\n if (currentLineItem && segments[1]) {\n const priceParts = segments[1].split(':');\n currentLineItem.priceQualifier = priceParts[0];\n currentLineItem.price = parseFloat(priceParts[1] || '0');\n }\n break;\n \n case 'UNT':\n // Message Trailer\n break;\n \n case 'UNZ':\n // Interchange Trailer\n break;\n }\n }\n \n // Add some summary info\n result.summary = {\n documentType: 'Return Order',\n documentNumber: result.orderDetails.documentNumber,\n orderDate: result.dates.find(d => d.qualifier === '137')?.date || '',\n lineItemCount: result.lineItems.length,\n totalQuantity: result.lineItems.reduce((sum, item) => sum + item.quantity, 0)\n };\n \n return result;\n}\n\n// Return the parsed EDI data\nconst ediMessage = $input.first().json.body;\n\nif (!ediMessage) {\n throw new Error('No EDI message found in input. Please provide the EDI message in the \"ediMessage\" property.');\n}\n\nconst parsedData = parseEDI(ediMessage);\nreturn { json: parsedData };"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "0fa4b446-bb37-48ab-a44b-8b2c52e2660b",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4100,
-1240
],
"parameters": {
"color": 7,
"width": 700,
"height": 620,
"content": "### 4. Store the Transactions in a Google Sheet\nThis block will filter the order based on the order type (Return Orders, Outbound Orders) extracted from the order information node. Results are stored in two distinct sheets of the same Google Sheet file.\n\n#### How to setup?\n- **Add Results in Google Sheets**:\n 1. Add your Google Sheet API credentials to access the Google Sheet file\n 2. Select the file using the list, an URL or an ID\n 3. Select the sheet in which the vocabulary list is stored\n 4. You don't need to create columns as the mapping is automatic.\n [Learn more about the Google Sheet Node]({{ $env.WEBHOOK_URL }}"
},View on GitHub (pinned to 94007c1445)
Solutions
- Run the trigger once and inspect the first item's json keys to find where the EDI string actually is.
- Read the message with a fallback chain and fix the error text (see exampleFix).
- If the source is Gmail, add an extract-text step before this node.
- Pin a sample EDIFACT message so the parser can be tested standalone.
Example fix
// before
const ediMessage = $input.first().json.body;
if (!ediMessage) {
throw new Error('No EDI message found in input. Please provide the EDI message in the "ediMessage" property.');
}
// after
const j = $input.first().json;
const ediMessage = j.body ?? j.ediMessage ?? j.message ?? j.text;
if (typeof ediMessage !== 'string' || !ediMessage.includes("'")) {
throw new Error(`No EDI message found (looked in body/ediMessage/message/text; got keys: ${Object.keys(j).join(', ')})`);
} Defensive patterns
Strategy: validation
Validate before calling
const j = $input.first().json;
const edi = [j.body, j.ediMessage, j.message, j.text].find(v => typeof v === 'string' && v.includes("'"));
if (!edi) throw new Error(`No EDI message (keys present: ${Object.keys(j).join(', ')})`); Type guard
function isEdifactString(v) {
return typeof v === 'string' && /UNB\+|UNH\+|UNA/.test(v);
} Prevention
- Make error messages name the property the code actually reads (body, not ediMessage).
- Normalize the trigger payload in one dedicated Set/Code node right after the trigger.
- Detect EDIFACT content (UNA/UNB/UNH segments) rather than just truthiness before parsing.
When it happens
Trigger: The webhook/gmail input delivers the raw EDI string under a different key — $json.message, $json.text, $json.payload, or (for Gmail triggers) a nested body structure — so json.body is undefined. An empty message body also triggers it.
Common situations: Webhook trigger posting the EDI as a form field or plain text body that n8n nests elsewhere; Gmail trigger where the EDI is in the email plain/html body requiring extraction first; switching the trigger type after the workflow was built; test executions with no sample data pinned.
Related errors
- Invalid quantity: ${input["Quantity Received"]}
- Invalid price: ${input["Unit Price"]}
- Invalid quantity Requested: ${quantityRequested}. Must be gr
- Product ID is missing
- Invalid quantity requested: ${quantityRequested}
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/7c343a779c636867.
Report an issue: GitHub.