Unexpected token '<' ... is not valid JSON: إيش يعني؟

خطأ Unexpected token '<', "<!DOCTYPE "... is not valid JSON يعني إن منتجك طلب بيانات ووصلته صفحة HTML. خمسة أسباب تسببه بعد النشر وكيف تلقى سببك.

22 أكتوبر 2026 (11 جمادى الأولى 1448 هـ) · قراءة 4 دقائق · كتبها م. معاذ أحمد

تفتح صفحة في منتجك، والبيانات ما تظهر، وفي Console تلقى سطر أحمر شكله:

SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

وفي Firefox يطلع بصيغة ثانية: JSON.parse: unexpected character at line 1 column 1. المعنى واحد: الكود طلب بيانات من سيرفر وكان ينتظر JSON، ووصلته صفحة HTML. والحرف < هو أول حرف في <!DOCTYPE html>، بداية أي صفحة ويب.

الخطأ نفسه مو المشكلة

هذي الرسالة عرَض، مو سبب. هي تقول لك إن الرد غلط، لكن ما تقول ليش. السبب الحقيقي في سؤال واحد: إيش الصفحة اللي رجعت بدل البيانات، ومن وين؟ والجواب تلقاه في دقيقة.

كيف تشوف الرد الحقيقي

  1. افتح الصفحة اللي فيها المشكلة، واضغط F12، وافتح تبويب Network.
  2. حدّث الصفحة، واختار من القائمة الطلب اللي يجيب البيانات (غالبًا نوعه fetch أو xhr).
  3. شوف ثلاث أشياء: الرابط الكامل اللي انطلب (Request URL)، ورقم الحالة (Status)، وتبويب Response.

إذا Response فيه صفحة HTML، اقرأها: أحيانًا هي صفحة موقعك نفسه، وأحيانًا صفحة 404 من الاستضافة، وأحيانًا صفحة تسجيل دخول أو صفحة تحقق من Cloudflare. كل وحدة تدلّك على سبب.

الأسباب الأشهر بعد النشر

1. الطلب راح لموقعك بدل سيرفرك

الكود يطلب /api/orders، وعلى جهازك كان فيه إعداد تحويل (proxy) في vite.config يرسل هالطلبات لسيرفرك المحلي. هذا الإعداد يشتغل في التطوير فقط. بعد النشر، الطلب يروح لاستضافة الواجهة، وما فيه شي اسمه /api/orders، فترجع لك صفحة موقعك نفسه بسبب قاعدة التوجيه اللي ترجّع index.html لكل رابط. علامته: رقم الحالة 200، والـ Response هو نفس صفحة موقعك.

2. رابط السيرفر ناقص

الكود يبني الرابط من متغير مثل VITE_API_URL، والمتغير ما انضاف في إعدادات النشر، فيصير الرابط شي مثل undefined/api/orders. علامته: تشوف كلمة undefined داخل Request URL. شرحنا ليش هالمتغيرات تختفي في درس المتغيرات اللي تصير undefined.

3. السيرفر نفسه متعطّل

السيرفر رجّع صفحة خطأ (500 أو 502) بصيغة HTML بدل رد منظّم. علامته: رقم حالة 500 أو أكثر. هنا الخطأ الحقيقي في سجل السيرفر، مو في المتصفح. شوف درس 502 و 504.

4. الرابط غلط أو الـ endpoint انحذف

مسار فيه حرف زايد، أو endpoint تغيّر اسمه بعد تعديل من الذكاء الاصطناعي وما تغيّر في الواجهة. علامته: رقم الحالة 404.

5. الطلب انحوّل لصفحة تسجيل الدخول أو صفحة تحقق

الجلسة انتهت، والسيرفر حوّل الطلب لصفحة الدخول. أو Cloudflare أو حماية ثانية أمام سيرفرك ردّت بصفحة تحقق. علامته: الـ Response صفحة فيها نموذج دخول أو رسالة تحقق.

من وين تبدأ

إذا الخطأ يطلع على الموقع المنشور فقط، وعلى جهازك كل شي تمام، ابدأ بالسببين 1 و2: هم الأشهر بعد أول نشر. وإذا كان يشتغل على الموقع المنشور ثم فجأة صار يطلع، ابدأ بـ 3 و5، لأن شي تغيّر في السيرفر أو في الجلسة، مو في الكود.

الحل الصح

الحل يعتمد على السبب اللي لقيته: سيرفر لازم ينشر ويكون له رابط واضح، أو متغير ينضاف في إعدادات النشر ثم تعيد النشر، أو مسار يتصحّح في الواجهة والسيرفر مع بعض.

وفوق هذا، الكود نفسه لازم يتأكد من الرد قبل ما يقرأه: إذا رقم الحالة مو ناجح، أو الرد مو JSON، يعرض للمستخدم رسالة واضحة ويسجّل الخطأ عندك، بدل ما ينهار بصمت.

الحل اللي لا تسويه

أشهر اقتراح من أدوات الذكاء الاصطناعي هنا إنها تلف الكود بـ try/catch وترجّع قائمة فاضية لما يفشل. الخطأ يختفي من Console، لكن المشكلة باقية: عميلك يشوف صفحة فاضية كأنه ما عنده طلبات، وأنت ما تدري إن فيه شي متعطّل. والأسوأ لو الصفحة صفحة دفع أو حجز، لأن المستخدم يحسب العملية ما تمّت ويعيدها.

تبي أحد يتتبّعه معك؟

إذا شفت الرد ومو واضح لك من وين جا، هذا بالضبط نوع المشاكل اللي تنحل في مكالمة استشارية: نتتبّع الطلب معك من المتصفح حتى السيرفر ونوصل لأصله. وإذا الطلب ما يوصل أصلًا ويطلع خطأ ثاني مثل Failed to fetch، شوف درس Failed to fetch.

عندك نفس المشكلة؟

علّمنا إيش صار بدون كلام تقني، ونقول لك إيش تحتاج وكم يكلّف.

ابدأ طلبك

بدون أي كلمة سر · عرض السعر مجاني