NBSP - kẻ giấu mặt khiến dữ liệu insert vào SQL Server qua n8n cứ bị NULL
Hiện tượng
Một workflow n8n dùng node Microsoft SQL để insert dữ liệu từ webhook vào SQL Server. Một vài cột luôn bị NULL sau mỗi lần chạy, dù nhìn ở bất kỳ đâu trong n8n (Input, Output các node, kể cả node ngay trước bước insert) dữ liệu vẫn hiển thị đầy đủ, không hề rỗng. Đã kiểm tra tên cột, thứ tự cột, trigger, default constraint, insert tay bằng SSMS — tất cả đều ổn. Vậy vấn đề nằm ở đâu?
Cách phát hiện
Copy tên field nghi vấn (ví dụ Address Bill to) từ ô cấu hình trong n8n, dán vào Notepad, lưu file với Encoding: UTF-8. Mở file đó lên bằng một trình xem hex, hoặc đơn giản hơn — paste chuỗi vào một đoạn code nhỏ để in ra mã Unicode của từng ký tự:
javascript
> const s = "Address Bill to"; // chuỗi copy từ n8n ra
> console.log([...s].map(c => c.charCodeAt(0).toString(16)));
Kết quả lộ ra: khoảng trắng giữa các từ không phải U+0020 (space thường) mà là U+00A0 — non-breaking space (NBSP).
NBSP là gì và vì sao nó gây lỗi
NBSP là một ký tự khoảng trắng đặc biệt, thường sinh ra khi copy nội dung từ Word, một số trang web, hoặc app chat — dùng để ngăn xuống dòng giữa hai từ. Nhìn bằng mắt, NBSP giống hệt dấu cách thường, nhưng về mã Unicode là hai ký tự hoàn toàn khác nhau:
| Ký tự | Mã Unicode | Nhìn thấy |
|---|---|---|
| Space thường | U+0020 | |
| Non-breaking space | U+00A0 | " " (giống hệt) |
Khi tên field trong n8n thực chất là Address\u00A0Bill\u00A0to nhưng phía so khớp (tên cột SQL, ô Columns, expression $json['Address Bill to']...) lại dùng space thường \u0020, hệ thống so khớp theo từng byte sẽ coi đây là hai chuỗi khác nhau → không tìm thấy giá trị tương ứng → insert ra NULL. Mọi thứ vẫn "trông đúng" trên UI vì trình duyệt render NBSP và space giống hệt nhau.
Cách khắc phục
Fix tận gốc: vào field bị lỗi, xoá tên field và gõ lại bằng bàn phím, không copy-paste, để chắc chắn dùng dấu cách thường.
Fix phòng ngừa (khi field name có nguy cơ bị copy-paste lại trong tương lai): thêm một node Code chuẩn hoá mọi tên field trước khi ghi vào SQL:
javascript
> const item = $input.first().json;
> const cleaned = {};
>
> for (const key in item) {
> cleaned[key.replace(/\u00A0/g, ' ').trim()] = item[key];
> }
>
> return [{ json: cleaned }];
Rà soát nhanh toàn bộ field đang dính NBSP:
javascript
> const item = $input.first().json;
> const report = Object.keys(item)
> .filter(key => key.includes('\u00A0'))
> .map(key => ({ key_loi: key, hien_thi: key.replace(/\u00A0/g, '·') }));
>
> return [{ json: { fields_bi_nbsp: report } }];
Bài học
Khi hai chuỗi "nhìn giống hệt nhau" mà logic so khớp lại thất bại một cách khó hiểu, hãy nghi ngờ ký tự ẩn — đặc biệt nếu dữ liệu từng đi qua copy-paste. Copy chuỗi ra Notepad, lưu với encoding UTF-8, rồi soi mã ký tự là cách đơn giản và hiệu quả để lộ ra những "kẻ giấu mặt" như NBSP.
All rights reserved