{"record":{"id":"143c590b71de110f","repo":"n8n-io/n8n","slug":"failed-to-decode-base64-attachment-data","errorCode":null,"errorMessage":"Failed to decode base64 attachment data","messagePattern":"Failed to decode base64 attachment data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/instance-ai/src/parsers/structured-file-parser.ts","lineNumber":376,"sourceCode":"\t\t}\n\t}\n\n\treturn { rawHeaders, allRows: parsed as Array<Record<string, unknown>> };\n}\n\n// ── Main parse function ─────────────────────────────────────────────────────\n\nexport function parseStructuredFile(\n\tattachment: AttachmentInfo,\n\tattachmentIndex: number,\n\tinput: ParseFileInput,\n): ParseFileOutput {\n\t// Decode base64\n\tlet decoded: Buffer;\n\ttry {\n\t\tdecoded = Buffer.from(attachment.data, 'base64');\n\t} catch {\n\t\tthrow new Error('Failed to decode base64 attachment data');\n\t}\n\n\tif (decoded.length > MAX_DECODED_SIZE_BYTES) {\n\t\tthrow new Error(formatSizeLimitMessage(decoded.length));\n\t}\n\n\tconst content = decoded.toString('utf-8');\n\tconst format = detectFormat(attachment.fileName, attachment.mimeType, input.format);\n\tif (!format || !isLegacyTabularFormat(format)) {\n\t\tthrow new Error(\n\t\t\t`Unsupported format for \"${attachment.fileName}\" (${attachment.mimeType}). Supported: csv, tsv, json`,\n\t\t);\n\t}\n\n\tconst hasHeader = input.hasHeader ?? true;\n\tconst startRow = input.startRow ?? 0;\n\tconst maxRows = Math.min(input.maxRows ?? DEFAULT_MAX_ROWS, MAX_ROWS_PER_CALL);\n\tconst warnings: string[] = [];","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/instance-ai/src/parsers/structured-file-parser.ts#L358-L394","documentation":"Documented as the catch around Buffer.from(attachment.data, 'base64') inside parseStructuredFile (structured-file-parser.ts:377). Node's Buffer.from(string,'base64') does not throw on invalid input — it discards non-base64 characters — so in current Node versions this branch is effectively unreachable. It exists as a defensive guard against future runtime changes.","triggerScenarios":"Only reachable if a future Node version or Buffer polyfill makes Buffer.from throw for malformed base64. Today, malformed base64 silently produces a short/empty buffer instead.","commonSituations":"Practically never seen on supported Node versions. If observed, it indicates a non-standard Buffer shim or a host that wraps Buffer.from to validate strict base64.","solutions":["Confirm attachment.data is valid base64 (e.g. /^[A-Za-z0-9+/]*={0,2}$/ with correct padding) before calling parseStructuredFile.","Check the Node version and any Buffer polyfills in the runtime.","If genuinely hit, re-encode the source bytes to base64 before attaching."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const BASE64_RE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;\nif (typeof attachment.data !== 'string' || !BASE64_RE.test(attachment.data)) {\n  throw new Error('attachment.data must be valid base64');\n}","typeGuard":"function isBase64String(v: unknown): v is string {\n  return typeof v === 'string' && /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(v);\n}","tryCatchPattern":"try { return parseStructuredFile(attachment, idx, input); }\ncatch (e) {\n  if (e instanceof Error && e.message === 'Failed to decode base64 attachment data') {\n    // re-encode the source bytes to base64 and retry\n  }\n  throw e;\n}","preventionTips":["Always encode attachments with Buffer.from(bytes).toString('base64').","Validate base64 shape before sending if the source is untrusted.","Confirm Node's Buffer.from is not shimmed in the host environment."],"tags":["base64","attachment-parsing","unreachable","buffer"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}