Tra cứu thông báo lỗi JSON: từ văn bản lỗi đến cách sửa
Kết luận: Tra cứu nguyên nhân theo đúng thông báo JSON.parse: 12 lỗi thường gặp trên Chrome, Firefox và Safari, bao gồm trang lỗi HTML, nội dung bị cắt và phân tích hai lần.

Điểm mấu chốt: khi xuất hiện lỗi JSON.parse, hãy nắm lấy vị trí và token trước; vị trí bằng 0 nghĩa là phải kiểm tra phản hồi HTML, BOM hoặc sai kiểu, còn thông báo "Expected" nghĩa là phải xem ký tự phía trước — đừng đọc lại từng dòng từ vị trí được báo.
Văn bản lỗi không phải tiếng ồn — nó chính là câu trả lời. Trình phân tích cho bạn biết nó đụng phải ký tự nào, nó kỳ vọng điều gì, và thực tế nhận được gì. Tra cứu theo thông báo lỗi hiệu quả hơn viết lại cả tài liệu bằng tay.
Mỗi lỗi JSON.parse() đều có ba phần: vị trí (một độ lệch ký tự, hoặc dòng/cột), kỳ vọng (Expected...), và thực tế (Unexpected token X, hoặc xxx is not valid JSON). Các engine diễn đạt khác nhau — Chrome và Node (V8) nói Expected ',' or '}' after property value in JSON at position 25, Firefox nói JSON.parse: expected ',' or '}' after property value in object at line 3 column 1, Safari nói JSON Parse error: Expected ',' or '}' — nhưng cả ba đều trỏ vào cùng một chỗ gãy cú pháp. Khi tra cứu một lỗi, hãy bỏ qua cách diễn đạt và nắm ba dữ kiện: ký tự nào, kỳ vọng gì, thực tế nhận được gì.
1. Bảng tra cứu 12 lỗi
Cột bên trái là đoạn dễ nhận ra nhất từ console của bạn (cách diễn đạt của V8). Các biến thể Firefox/Safari nằm trong ngoặc đơn.
| Văn bản lỗi (V8) | Nguyên nhân thật | Cách sửa |
|---|---|---|
Unexpected token < in JSON at position 0 |
API trả về HTML (trang 404, template 500, chuyển hướng đăng nhập, proxy fallback), không phải JSON | Kiểm tra response.status và Content-Type trước; đừng sửa JSON |
Unexpected end of JSON input |
Đầu vào rỗng hoặc bị cắt: body rỗng, 204, tải xuống gián đoạn, bản sao thiếu dòng cuối | Xử lý trường hợp rỗng, so sánh Content-Length để tìm chỗ bị cắt |
Unexpected token o / "[object Object]" is not valid JSON |
Một object đã được phân tích lại bị truyền vào JSON.parse() lần nữa và bị ép thành chuỗi |
Kiểm tra typeof; nếu là object thì dùng trực tiếp |
"undefined" is not valid JSON |
Biến chưa từng được gán (JSON.parse(undefined)) |
Khởi tạo giá trị dự phòng; kiểm tra trước khi phân tích |
Expected double-quoted property name in JSON |
Dấu phẩy cuối ({"a": 1,}); trình phân tích kỳ vọng một khóa nữa và gặp } |
Xóa dấu phẩy sau phần tử cuối |
Expected property name or '}' in JSON |
Khóa không đặt ngoặc kép hoặc đặt nháy đơn ({name: "Ada"}, {'name': 'Ada'}) |
Đặt mọi khóa trong ngoặc kép |
Expected ',' or '}' after property value in JSON |
Thiếu dấu phẩy ({"a": 1 "b": 2}) hoặc có comment sau một giá trị |
Thêm dấu phẩy; gỡ comment |
Unexpected token '/' |
Comment // hoặc /* */ bên trong JSON |
Xóa nó, hoặc phân tích cấu hình như JSONC |
Bad control character in string literal |
Xuống dòng, tab hoặc ký tự điều khiển U+0000–U+001F thô bên trong chuỗi | Viết \n; sinh bằng JSON.stringify |
Unterminated string in JSON |
Một chuỗi mở bằng " mà không bao giờ đóng, hoặc dấu ngoặc kép bên trong chưa escape |
Escape ngoặc kép bên trong thành \" |
Unexpected non-whitespace character after JSON |
Hai tài liệu trong một văn bản: {}{}, NDJSON, wrapper JSONP |
Tách theo dòng và phân tích từng phần, hoặc dùng trình phân tích NDJSON |
JSON.parse is not a function |
Biến của chính bạn che mất JSON toàn cục |
Đổi tên biến; đừng bao giờ đặt tên nó là JSON |
Hai lỗi đầu đáng xem kỹ hơn, vì không lỗi nào nghĩa là "JSON của bạn sai" — chúng nghĩa là "thứ bạn nhận được không phải thứ bạn tưởng".
2. Ba nguồn gốc phổ biến của lỗi vị trí 0
Vị trí 0 nghĩa là ký tự đầu tiên đã bất hợp lệ. Nếu không thấy gì đáng ngờ, có lẽ ký tự đó là vô hình. Ba nghi phạm thường gặp:
Thứ nhất: <, nghĩa là HTML. Đây là lỗi phân tích phổ biến nhất trong môi trường production. Một URL sai, một phiên đăng nhập đã hết hạn bị gateway chuyển hướng, hoặc một template lỗi máy chủ — body bắt đầu bằng <!DOCTYPE html> và trình phân tích bỏ cuộc ngay ký tự đầu. Việc đúng cần làm là mở bảng Network và đọc phản hồi thô, rồi sửa lời gọi API, chứ không phải sửa JSON.
Thứ hai: BOM hoặc ký tự độ rộng bằng không. Các tệp do Notepad trên Windows lưu thường bắt đầu bằng BOM UTF-8 (\uFEFF), và văn bản sao chép từ trang web hoặc ứng dụng chat có thể mang theo khoảng trắng độ rộng bằng không (\u200B–\u200D). Bạn không thấy, trình phân tích thấy rõ:
// Strip BOM and zero-width characters before parsing
const cleaned = raw.replace(/^\uFEFF/, '').replace(/[\u200B-\u200D]/g, '');
const data = JSON.parse(cleaned);
Thứ ba: sai kiểu. JSON.parse(undefined) báo "undefined" is not valid JSON; JSON.parse(someObject) báo Unexpected token o (object bị ép thành "[object Object]", và o bất hợp lệ ở vị trí 1). Cả hai đều nghĩa là "dữ liệu đã được phân tích rồi" hoặc "chưa từng có dữ liệu". Hãy kiểm tra kiểu, không phải cú pháp:
let data = text;
if (typeof data === 'string') {
data = JSON.parse(data); // Parse only when it really is a string
}
3. Vị trí trỏ về phía sau; nguyên nhân nằm ở phía trước
Hai lỗi đánh lừa bạn về vị trí, và chúng là hai mục bị đọc sai nhiều nhất trong bảng:
- Thiếu dấu phẩy:
{"a": 1 "b": 2}báoExpected ',' or '}' after property valuetại dòng"b". Báo cáo là đúng, nhưng chỗ cần sửa lại nằm ở cuối dòng trước. - Thiếu ngoặc đóng: lồng nhau sâu mà thiếu một
}hoặc]khiến trình phân tích nuốt mọi thứ đến hết đầu vào và báoUnexpected end of JSON input. Vị trí là cuối tệp; khoảng trống thật có thể nằm xa về phía trước. Hãy tìm ngược dấu{hoặc[chưa đóng gần nhất — đếm cặp ngoặc đáng tin hơn dò bằng mắt.
Kỹ thuật tổng quát là chia đôi: cắt phần văn bản trước vị trí được báo và phân tích riêng nó. Nếu nó qua, vấn đề nằm gần vị trí được báo; nếu không, chia đôi xa hơn về phía trước. Ranh giới của đoạn hỏng đầu tiên chính là chỗ lỗi thật. Với tệp lớn, hãy định dạng tài liệu trước — khi thụt lề đã thẳng hàng, cấp bị thiếu sẽ lộ ra trong nháy mắt (trình định dạng JSON trực tuyến làm việc này ổn).
4. Bốn trạng thái "khỏe giả" phân tích qua mà vẫn sai
Tệ hơn một lỗi là không lỗi mà dữ liệu lại sai. Trong cả bốn trường hợp, JSON đều hợp lệ và trình phân tích thấy vui vẻ — vấn đề nằm ở hình dạng dữ liệu:
- Mã hóa hai lần: cả tài liệu bị
JSON.stringifyhai lần, nên phân tích ra một chuỗi chứ không phải object. Nếutypeof result === 'string', hãy phân tích lại — nhưng hãy tìm và sửa việc tuần tự hóa hai lần tại nguồn. - Khóa trùng âm thầm ghi đè:
{"name": "Tom", "name": "Jerry"}là JSON hợp lệ, hầu hết trình phân tích không phàn nàn, và giá trị thứ hai thắng. Điều này cắn khi gộp dữ liệu từ nhiều nguồn; hãy phát hiện nó bằng một bộ xác thực JSON nghiêm ngặt trước khi nó cắn bạn. - NDJSON bị coi là một tài liệu: các API streaming phát ra một object mỗi dòng; phân tích cả văn bản sẽ hỏng với
Unexpected non-whitespace character after JSON. Hãy tách theo\nvà phân tích từng dòng. - Mất độ chính xác số âm thầm: các số nguyên vượt
2^53 - 1(ID snowflake) trở về với các chữ số cuối bị san phẳng, mà không có lỗi nào. Hãy truyền ID dưới dạng chuỗi.
Sợi chỉ chung: trình phân tích tin rằng mọi thứ đều ổn. Vì vậy khi dữ liệu API trông sai, hãy in 80 ký tự đầu của văn bản thô và typeof của nó trước — xác nhận hình dạng rồi mới bàn đến nội dung.
5. Khiến lỗi không thể xảy ra ngay từ lúc viết
Bảng tra cứu là công cụ hậu kiểm; phòng ngừa là công cụ tiên kiểm. Bốn thói quen chặn được hầu hết lỗi trước khi chúng xảy ra:
// 1. Two checks before parsing any response
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: the API returned no data`);
}
const contentType = response.headers.get('content-type') ?? '';
if (!contentType.includes('application/json')) {
throw new Error(`Expected JSON, got ${contentType}`);
}
const data = await response.json(); // 2. json() already parses — do not parse again
- Tuần tự hóa để sinh, đừng nối chuỗi:
JSON.stringify()xử lý dấu ngoặc kép, xuống dòng và ký tự điều khiển một cách chính xác; chuỗi tự ghép là nguồn hàng đầu củaBad control charactervàUnterminated string. - Luôn bắt lỗi: lỗi
JSON.parseđược ném ra là một cú crash đồng bộ trừ khi có thứ gì đó bắt nó. Với đầu vào không tin cậy — localStorage, tệp bên ngoài — khối catch cần một giá trị mặc định hoặc báo lỗi tường minh. - Giao cấu trúc cho Schema: cú pháp hợp lệ không có nghĩa là cấu trúc hợp lệ. Thiếu trường và sai kiểu thuộc về xác thực JSON Schema tại biên; xem JSON Schema giải quyết điều gì.
6. Lối quyết định nhanh
Cô đọng cả bài viết thành một thứ tự quyết định. Khi thấy lỗi, hãy nắm vị trí và token trước:
- Vị trí 0 → kiểm tra ba nguồn:
<(HTML), BOM, sai kiểu; end of input→ kiểm tra body rỗng hoặc bị cắt, rồi tìm ngược các ngoặc chưa đóng;Expected ...→ nhìn ký tự phía trước; thường là thiếu dấu phẩy hoặc dấu ngoặc kép;after JSON data→ nhiều tài liệu bị nối với nhau; tách theo dòng;- Phân tích qua nhưng dữ liệu trông sai → chạy bốn kiểm tra "khỏe giả".
Kết hợp với quy trình phân loại từng bước trong cách sửa lỗi phân tích JSON, 90% vấn đề phân tích sẽ được giải quyết trong vòng năm phút. Hãy đánh dấu chính văn bản lỗi — đó là bản ghi gỡ lỗi mà trình phân tích viết sẵn cho bạn, cách diễn đạt của nó thay đổi ba năm một lần, và một lần tra cứu là đủ dùng cả năm.
"Unexpected token in JSON" nghĩa là gì?
Trình phân tích đụng phải một ký tự bất hợp lệ tại vị trí đó trong ngữ pháp JSON. Token chính là ký tự bị từ chối: < thường nghĩa là API trả về HTML, ' nghĩa là dấu nháy đơn, / nghĩa là comment, và một chữ cái thông thường thường nghĩa là khóa không đặt ngoặc kép hoặc một literal chỉ có trong JavaScript như undefined hay NaN. Hãy đọc token trước, rồi đến vị trí, và nguyên nhân sẽ thu hẹp còn một.
Làm sao sửa "Unexpected end of JSON input"?
Hai nguồn: đầu vào rỗng (body phản hồi rỗng, hoặc chuỗi rỗng trong localStorage) hoặc đầu vào bị cắt (tải xuống gián đoạn, bản sao thiếu dòng cuối, giới hạn kích thước). Xử lý trường hợp rỗng bằng if (!text) return; sau đó kiểm tra tính đầy đủ và đóng {, [ hoặc " chưa đóng gần nhất. Lưu ý lỗi cũng có thể đến từ một ngoặc bị thiếu ở sâu — vị trí chỉ tình cờ nằm ở cuối tệp.
Vì sao Chrome, Firefox và Safari báo lỗi khác nhau?
Ba trình duyệt dùng các JS engine khác nhau (V8, SpiderMonkey, JavaScriptCore), và mỗi engine diễn đạt lỗi theo cách riêng; MDN ghi lại tất cả biến thể chính thức. Nhưng cả ba lỗi đều mang cùng ba yếu tố — vị trí, kỳ vọng, thực tế — với ngữ nghĩa tương ứng một-một. Hãy chuyển về cách diễn đạt của V8 và dùng bảng này nguyên trạng.
Vị trí lỗi trỏ đến một chỗ trông có vẻ ổn — giờ phải làm sao?
Lỗi thật nằm sớm hơn. Các trường hợp điển hình: thiếu dấu phẩy (báo ở dòng kế tiếp) và thiếu ngoặc đóng (báo ở cuối tệp). Hãy đi ngược từ vị trí được báo, từng token một, hoặc chia đôi: phân tích riêng nửa đầu, và ranh giới của đoạn hỏng đầu tiên chính là chỗ lỗi thật.