N8n Form Submission Issue - Ticket Information

Describe the problem/error/question

  • Error Message: “Problem submitting response. Please try again or contact support if the problem persists”

  • Frequency: Intermittent - occurs sometimes, not consistently

  • Trigger: File uploads through n8n forms

  • Pattern: Error depends on the specific file being uploaded, regardless of file extension

  • Impact: Form submissions fail unpredictably

What is the error message (if any)?

  • Error Message: “Problem submitting response. Please try again or contact support if the problem persists”

Please share your workflow



Share the output returned by the last node

Information on your n8n setup

  • n8n version: 1.107.3
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app): n8n cloud
  • Operating system: windows

Hello @Mariano_Carames , how are you?

Could you export the workflow code or just the “code node” code, so I can accurately evaluate the problem?

{“nodes”: [{“parameters”: {“formTitle”: “Optimización de base de emails”,“formDescription”: “Por favor adjunte su base de email marketing en formato CSV. A la brevedad recibiras por corre un archivo con la base pre filtrada.”,“formFields”: {“values”: [{“fieldLabel”: “Business Unit”,“requiredField”: true},{“fieldLabel”: “¿Donde enviamos la base?”,“placeholder”: “[email protected]”,“requiredField”: true},{“fieldLabel”: “Base de datos a optimizar”,“fieldType”: “file”,“acceptFileTypes”: “.csv”,“requiredField”: true}]},“options”: {}},“type”: “n8n-nodes-base.formTrigger”,“typeVersion”: 2.2,“position”: [160,-48],“id”: “c876de43-cbca-4167-85cd-d4df7b37d200”,“name”: “On form submission”,“webhookId”: “0d2464b1-380e-4671-a17e-ddbd9e51f63e”},{“parameters”: {“toRecipients”: “={{ $(‘On form submission’).item.json[‘¿Donde enviamos la base?’] }}”,“subject”: “Base de datos optimizada!”,“bodyContent”: “=Hola, te envio la base limpia.\n\nSon 2 archivos uno con los OK(OK.csv) y otro con los NOK (NOK.csv).\n\nSaludos!”,“additionalFields”: {“attachments”: {“attachments”: [{“binaryPropertyName”: “OK”},{“binaryPropertyName”: “NOK”}]}}},“type”: “n8n-nodes-base.microsoftOutlook”,“typeVersion”: 2,“position”: [704,-48],“id”: “5df9baa7-2836-4a3d-9892-8cc4857b664e”,“name”: “Send a message”,“webhookId”: “930d36f2-e1a9-4608-9bfe-f37c78c65d6b”,“credentials”: {“microsoftOutlookOAuth2Api”: {“id”: “yKQhoG6fKR2fo9hW”,“name”: “Microsoft Outlook account 3”}}},{“parameters”: {“jsCode”: “/* CODE NODE (todo en uno) \nToma el archivo del campo del Form: “Base de datos a optimizar” (binary),\nparsea el CSV, valida Email/Phone, separa en OK y NOK y crea dos binarios:\n - binary.ok  → OK.csv\n - binary.nok → NOK.csv\nNo setea to/subject/body ni otros campos del form.\n*/\n\n// === Nombre EXACTO del campo de archivo del Form ===\nconst FILE_PROP = ‘Base de datos a optimizar’;\n\n// === Config de validación ===\nconst EMAIL_COL = ‘Email’;\nconst PHONE_COL = ‘Phone’;\n\nconst disposable = new Set([‘yopmail.com’,‘mailinator.com’,‘guerrillamail.com’,‘10minutemail.com’,‘tempmail.com’,‘sharklasers.com’,‘dispostable.com’]);\nconst reserved = new Set([‘example.com’,‘example.org’,‘example.net’,‘test.com’]);\nconst emailRegex = /+@[^\s@]+\.[^\s@]{2,}$/i;\n\nconst AREA_CODES = new Set([\n  ‘11’,‘221’,‘223’,‘230’,‘236’,‘249’,‘260’,‘261’,‘264’,‘266’,‘280’,‘2901’,‘2920’,‘2964’,‘297’,\n  ‘341’,‘343’,‘351’,‘362’,‘370’,‘376’,‘379’,‘381’,‘383’,‘385’,‘387’,‘388’\n]);\n\n// Columnas del CSV original (ajustá si cambia tu input)\nconst BASE_COLS = [\n  ‘_’,‘Id’,‘Name’,‘Email’,‘Phone’,‘Tipo__c’,‘Account’,‘Account.CUIT__c’,‘Account.Name’,\n  ‘Account.RecordType’,‘Account.RecordType.Name’,‘RecordType’,‘RecordType.Name’,‘CreatedDate’\n];\n\n// Columnas derivadas que agregamos\nconst DERIVED_COLS = [\n  ‘Email_Normalized’,‘Email_Empty’,‘Email_FakeScore’,‘Email_FakeReasons’,\n  ‘Phone_Normalized’,‘Phone_Valid’,‘Phone_Reason’,‘StatusReasons’,‘Status’\n];\n\n// === Helpers ===\nfunction getSLD(domain) {\n  const p = (domain || ‘’).split(‘.’).filter(Boolean);\n  return p.length >= 2 ? p[p.length - 2] : (domain || ‘’);\n}\nfunction alnum(s) { return (s || ‘’).toString().replace(/[^a-z0-9]/gi, ‘’); }\n\nfunction normalizePhoneAR(raw) {\n  let s = (raw == null ? ‘’ : String(raw)).trim();\n  if (!s) return { e164: ‘’, ok: false, why: ‘empty’ };\n  s = s.replace(/^\s*00/,‘+’);\n  let s2 = s.replace(/[^\d+]/g,‘’);\n  if (/^54\d+/.test(s2)) s2 = ‘+’ + s2;\n  if (s2.charAt(0) !== ‘+’) {\n    let digits = s2.replace(/\D/g,‘’);\n    if (digits.charAt(0) === ‘0’) digits = digits.slice(1);\n    s2 = ‘+54’ + digits;\n  }\n  const m = /^\+54(9?)(\d+)$/.exec(s2);\n  if (!m) return { e164: s2, ok: false, why: ‘wrong_country_or_format’ };\n\n  const has9 = m[1] === ‘9’;\n  let rest = m[2];\n  if (rest.charAt(0) === ‘0’) rest = rest.slice(1);\n  if (rest.slice(0,2) === ‘15’) rest = rest.slice(2);\n\n  if (has9 && rest.length !== 10) return { e164: ‘+549’ + rest, ok: false, why: ‘length_invalid_mobile_expected_10’ };\n  if (!has9 && rest.length !== 10) return { e164: ‘+54’ + rest, ok: false, why: ‘length_invalid_expected_10’ };\n\n  const areas = Array.from(AREA_CODES).sort((a,b)=> b.length-a.length);\n  let area = null;\n  for (let i=0;i<areas.length;i++){ if (rest.indexOf(areas[i])===0){ area=areas[i]; break; } }\n  if (!area) return { e164: ‘+54’ + (has9?‘9’:‘’) + rest, ok: false, why: ‘unknown_area_code’ };\n\n  const subscriber = rest.slice(area.length);\n  if (subscriber.length < 6 || subscriber.length > 8) return { e164: ‘+54’ + (has9?‘9’:‘’) + rest, ok: false, why: ‘subscriber_length_invalid’ };\n  if (area === ‘11’ && subscriber.length !== 8) return { e164: ‘+54’ + (has9?‘9’:‘’) + rest, ok: false, why: ‘amba_length_invalid’ };\n\n  return { e164: ‘+54’ + (has9?‘9’:‘’) + area + subscriber, ok: true, why: ‘ok’ };\n}\n\n// === CSV Parser (lee el binario del Form) ===\nconst bin = items?.[0]?.binary?.[FILE_PROP];\nif (!bin || !bin.data) {\n  throw new Error(No llegó el archivo en binary[\"${FILE_PROP}\"]. Verificá el campo File del Form.);\n}\nconst csvText = Buffer.from(bin.data, ‘base64’).toString(‘utf8’);\n\n// Parser simple con comillas y coma\nfunction parseCsv(text, delimiter = ‘,’) {\n  const rows = ;\n  let i = 0, cur = ‘’, inQuotes = false;\n  const pushCell = (arr) => { arr.push(cur); cur = ‘’; };\n  const pushRow  = (arr) => { rows.push(arr); };\n  let row = ;\n\n  while (i < text.length) {\n    const ch = text[i];\n\n    if (inQuotes) {\n      if (ch === ‘“’) {\n        if (text[i+1] === ‘”’) { cur += ‘“’; i += 2; continue; }\n        inQuotes = false; i++; continue;\n      }\n      cur += ch; i++; continue;\n    }\n\n    if (ch === ‘”’) { inQuotes = true; i++; continue; }\n    if (ch === delimiter) { pushCell(row); i++; continue; }\n    if (ch === ‘\r’) { i++; continue; } // normalizar CRLF\n    if (ch === ‘\n’) { pushCell(row); pushRow(row); row = ; i++; continue; }\n\n    cur += ch; i++;\n  }\n  pushCell(row);\n  if (row.length > 1 || (row.length === 1 && row[0] !== ‘’)) pushRow(row);\n  return rows;\n}\n\nconst rows = parseCsv(csvText, ‘,’);\nif (!rows.length) throw new Error(‘CSV vacío’);\n\n// headers + filas a objetos\nconst headers = rows[0];\nconst dataRows = rows.slice(1).map(r => {\n  const o = {};\n  headers.forEach((h, idx) => { o[h] = r[idx] ?? ‘’; });\n  return o;\n});\n\n// === Validación y enriquecimiento ===\nconst processed = dataRows.map(row => {\n  // EMAIL\n  const original = (row[EMAIL_COL] == null ? ‘’ : String(row[EMAIL_COL])).trim();\n  const norm = original.toLowerCase();\n  let local = ‘’, domain = ‘’;\n  const parts = norm.split(‘@’);\n  if (parts.length === 2) { local = parts[0]; domain = parts[1]; }\n  const sld = getSLD(domain);\n\n  const emailReasons = ;\n  let score = 0;\n\n  const emailEmpty = (norm === ‘’);\n  if (emailEmpty) {\n    emailReasons.push(‘email_empty’);\n  } else {\n    if (!emailRegex.test(norm)) { emailReasons.push(‘email_syntax_invalid’); score += 3; }\n    if (/(test|fake|prueba|demo|asdf|qwer)/i.test(norm)) { emailReasons.push(‘keyword_fake’); score += 3; }\n    if (reserved.has(domain)) { emailReasons.push(‘reserved_domain’); score += 3; }\n    if (disposable.has(domain)) { emailReasons.push(‘disposable_domain’); score += 3; }\n    if (local.length <= 2) { emailReasons.push(‘local_too_short’); score += 2; }\n    if (sld.length <= 2) { emailReasons.push(‘domain_sld_too_short’); score += 2; }\n    if (alnum(local) && alnum(local) === alnum(sld)) { emailReasons.push(‘local_equals_domain’); score += 1; }\n    if (/^([a-z0-9])\1{2,}$/i.test(alnum(local)) && /^([a-z0-9])\1{2,}$/i.test(alnum(sld))) {\n      emailReasons.push(‘repeated_char_pattern’); score += 2;\n    }\n  }\n\n  // PHONE\n  const p = normalizePhoneAR(row[PHONE_COL]);\n\n  // STATUS\n  const hardFailEmail = emailEmpty || emailReasons.includes(‘email_syntax_invalid’);\n  const hardFailPhone = !p.ok;\n  const localEqDomain = (alnum(local) && alnum(local) === alnum(sld) && norm !== ‘’);\n  const scoreBasedFake = (score >= 3);\n\n  const statusIsFake = hardFailEmail || hardFailPhone || scoreBasedFake || localEqDomain;\n  const status = statusIsFake ? ‘FAKE’ : ‘OK’;\n\n  const statusReasons = ;\n  if (emailEmpty) statusReasons.push(‘email_empty’);\n  if (emailReasons.includes(‘email_syntax_invalid’)) statusReasons.push(‘email_syntax_invalid’);\n  if (localEqDomain) statusReasons.push(‘local_equals_domain’);\n  if (!p.ok) statusReasons.push(‘phone_invalid:’ + p.why);\n  for (const rr of emailReasons) {\n    if (rr !== ‘email_empty’ && rr !== ‘email_syntax_invalid’) statusReasons.push(rr);\n  }\n\n  return {\n    …row,\n    Email_Normalized: norm,\n    Email_Empty: emailEmpty ? ‘Yes’ : ‘No’,\n    Email_FakeScore: score,\n    Email_FakeReasons: emailReasons.join(‘|’),\n    Phone_Normalized: p.e164,\n    Phone_Valid: (p.ok ? ‘Yes’ : ‘No’),\n    Phone_Reason: p.why,\n    StatusReasons: statusReasons.join(‘|’),\n    Status: status\n  };\n});\n\n// === Split y serializar a CSV ===\nconst okRows  = processed.filter(r => String(r.Status).toUpperCase() === ‘OK’);\nconst nokRows = processed.filter(r => String(r.Status).toUpperCase() !== ‘OK’);\n\n// headers finales (base + dinámicas + derivadas)\nfunction dedupe(arr){ return Array.from(new Set(arr)); }\nconst dynamicKeys = processed.length ? Object.keys(processed[0]) : ;\nconst finalHeaders = dedupe([…BASE_COLS, …dynamicKeys, …DERIVED_COLS]);\n\nfunction toCsv(rows, headers) {\n  const escape = (v) => {\n    let s = v == null ? ‘’ : String(v);\n    s = s.replace(/\r\n/g, ‘\n’); // normaliza saltos\n    if (/[",\n]/.test(s)) s = \"${s.replace(/\"/g, '\"\"')}\";\n    return s;\n  };\n  const head = headers.join(‘,’);\n  const body = rows.map(r => headers.map(h => escape(r[h])).join(‘,’)).join(‘\n’);\n  return head + ‘\n’ + body;\n}\n\nconst okCsv  = toCsv(okRows,  finalHeaders);\nconst nokCsv = toCsv(nokRows, finalHeaders);\n\n// === OUTPUT: 1 item con dos binarios (ok y nok) y sólo métricas en JSON ===\nreturn [{\n  json: {\n    ok_count: okRows.length,\n    nok_count: nokRows.length\n    // No incluimos mail/subject/body ni otros campos del form.\n  },\n  binary: {\n    ok: {\n      data: Buffer.from(okCsv,  ‘utf8’).toString(‘base64’),\n      fileName: ‘OK.csv’,\n      mimeType: ‘text/csv’\n    },\n    nok: {\n      data: Buffer.from(nokCsv, ‘utf8’).toString(‘base64’),\n      fileName: ‘NOK.csv’,\n      mimeType: ‘text/csv’\n    }\n  }\n}];”},“type”: “n8n-nodes-base.code”,“typeVersion”: 2,“position”: [432,-48],“id”: “79e3898d-b9c6-4301-816e-e8e30f028604”,“name”: “Code”}],“connections”: {“On form submission”: {“main”: [[{“node”: “Code”,“type”: “main”,“index”: 0}]]},“Send a message”: {“main”: []},“Code”: {“main”: [[{“node”: “Send a message”,“type”: “main”,“index”: 0}]]}},“pinData”: {},“meta”: {“templateCredsSetupCompleted”: true,“instanceId”: “58f43889f3a29b9e60551833cfcaff1814838f9eac2a9b6d7bbd7721c41c7b38”}}

@Mariano_Carames

It’s not possible to access the workflow that way; please download the workflow JSON and send it here.

I tried to put the JSON but it won’t let me, I get the following message.

From what I’ve been seeing, it’s because of the number of rows the CSV has. What is the maximum number of rows/columns/fields that a CSV/Excel/etc. can have?

To include the workflow, click this button

And enter the json code (not the file)

Regarding the csv, if it is what is sent in the form trigger, it could be, but generally csv files are lightweight.