Zie619/n8n-workflows · error · Error
PII column names are missing in the input data.
Error message
PII column names are missing in the input data.
What it means
Thrown by the 'Remove PII columns' Code node when the first input item lacks a json.data string. The node expects a specific multi-item layout: input[0].json.data holds a comma-separated list of PII column names, input[1].json.originalFilename holds the file name, and input[2+] are the data rows. If item 0 has no .data property, the PII column list cannot be built and the node aborts.
Source
Thrown at workflows/Splitout/1637_Splitout_Code_Automation_Triggered.json:226
"parameters": {
"options": {
"destinationFieldName": "data"
},
"fieldToSplitOut": "message.content.content"
},
"typeVersion": 1,
"notes": "This splitOut node performs automated tasks as part of the workflow."
},
{
"id": "4207dc71-5b0e-4780-9f23-00f5a7fc3862",
"name": "Remove PII columns",
"type": "n8n-nodes-base.code",
"position": [
580,
260
],
"parameters": {
"jsCode": "// Input: All items from the previous node\nconst input = $input.all();\n\n// Step 1: Extract the PII column names from the first item\nconst firstItem = input[0];\nif (!firstItem.json.data || !firstItem.json.data) {\n throw new Error(\"PII column names are missing in the input data.\");\n}\nconst piiColumns = firstItem.json.data.split(',').map(col => col.trim());\n//console.log(\"PII Columns to Remove:\", piiColumns);\n\n// Step 2: Remove the first two items and process the remaining rows\nlet rows = input.slice(2).map(item => item.json); // Exclude the first item\n//console.log(\"Rows to convert (before skipping last):\", rows);\n\n\n// Ensure there are rows to process\nif (rows.length === 0) {\n throw new Error(\"No rows to convert to CSV.\");\n}\n\n// Step 3: Remove PII columns from each row\nconst sanitizedRows = rows.map(row => {\n const sanitizedRow = { ...row }; // Copy the row\n piiColumns.forEach(column => delete sanitizedRow[column]); // Remove PII columns\n return sanitizedRow;\n});\n//console.log(\"Sanitized Rows:\", sanitizedRows);\n\n// Step 4: Extract headers from sanitized rows\nconst headers = Object.keys(sanitizedRows[0]); // Extract updated headers\n//console.log(\"CSV Headers:\", headers);\n\n// Step 5: Convert rows to CSV format\nconst csvRows = [\n headers.join(','), // Add header row\n ...sanitizedRows.map(row => \n headers.map(header => String(row[header] || '').replace(/,/g, '')).join(',') // Match headers with rows\n )\n];\n\n// Join all rows with a newline character\nconst csvContent = csvRows.join('\\n');\n//console.log(\"CSV Content:\", csvContent);\n\nconst originalFileName = input[1].json.originalFilename;\n\n// Step 7: Generate a new filename\nconst fileExtension = originalFileName.split('.').pop();\nconst baseName = originalFileName.replace(`.${fileExtension}`, '');\nconst newFileName = `${baseName}_PII_removed.${fileExtension}`;\n//console.log(\"New Filename:\", newFileName);\n\n// Step 8: Return the CSV content and filename as JSON\nreturn [\n {\n json: {\n fileName: newFileName, // New file name\n content: csvContent // CSV content as plain text\n }\n }\n];\n"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "e9f25ee7-cd00-4496-9062-5d57cab5788d",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-300,
-220
],
"parameters": {
"height": 260,
"content": "## Remove PII from CSV Files\nThis workflow monitors a Google Drive folder for new CSV files, identifies and removes PII columns using OpenAI, and uploads the sanitized file back to the drive. It requires Google Drive and OpenAI integrations with API access enabled."
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."View on GitHub (pinned to 94007c1445)
Solutions
- Pin and inspect $input.all() upstream: verify item 0 contains a comma-separated column string in json.data and item 1 contains originalFilename.
- Fix the upstream node so the PII header item and filename item are emitted in positions 0 and 1 (e.g., adjust the Set/splitOut ordering).
- Harden the guard: also check typeof firstItem.json.data === 'string' and validate input[1]?.json?.originalFilename before use.
- If the payload shape has permanently changed (e.g., columns now arrive as an array), parse accordingly: Array.isArray(d) ? d : d.split(',').
Example fix
// before
if (!firstItem.json.data || !firstItem.json.data) {
throw new Error("PII column names are missing in the input data.");
}
const piiColumns = firstItem.json.data.split(',').map(col => col.trim());
const originalFileName = input[1].json.originalFilename;
// after - validate the whole contract up front
const headerItem = input[0]?.json;
const fileItem = input[1]?.json;
if (typeof headerItem?.data !== 'string' || headerItem.data.trim() === '') {
throw new Error(`PII column names are missing in the input data (item 0 keys: ${Object.keys(headerItem || {}).join(',')})`);
}
if (typeof fileItem?.originalFilename !== 'string' || !fileItem.originalFilename) {
throw new Error('originalFilename is missing on input item 1.');
}
const piiColumns = headerItem.data.split(',').map(col => col.trim());
const originalFileName = fileItem.originalFilename; Defensive patterns
Strategy: validation
Validate before calling
// Contract check before any processing:
const header = input[0]?.json;
const fileMeta = input[1]?.json;
const rows = input.slice(2);
const ok =
typeof header?.data === 'string' && header.data.trim() !== '' &&
typeof fileMeta?.originalFilename === 'string' && fileMeta.originalFilename !== '' &&
rows.length > 0;
if (!ok) {
throw new Error(`Unexpected input layout. Item counts: ${input.length}; item0 keys: ${Object.keys(header || {}).join(',')}`);
} Type guard
const isPiiLayout = (items) => items.length >= 3 && typeof items[0]?.json?.data === 'string' && typeof items[1]?.json?.originalFilename === 'string' && typeof items[2]?.json === 'object';
Prevention
- Validate the full multi-item contract (header item, filename item, rows) in one guard instead of checking the same field twice.
- Pin a sample file run so the parser's item layout is locked in and visible.
- When swapping the file-reader node, re-check item order and key names before re-enabling the workflow.
When it happens
Trigger: The upstream node (spreadsheet/file parser) emitted items in a different order or shape, json.data is an object/array instead of the expected comma-separated string, the file was empty so only one item arrived, or a prior node was changed to pass rows starting at index 0.
Common situations: Reordering items between nodes, switching the file parser (Read PDF/CSV vs Google Sheets) which changes item structure, or a config change where the PII-column header row is no longer the first item. Note the guard itself is buggy: it checks !firstItem.json.data twice instead of also validating input[1].originalFilename, so a missing filename fails later with an unrelated TypeError.
Related errors
- monthly_searches data is missing or not an array from Loop O
- Approved quantity must be greater than 0
- The video ID parameter is empty.
- One or more input arrays are empty. Check your previous node
- Invalid data structure
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/56620254f9f70895.
Report an issue: GitHub.