حل خطأ 422 Unprocessable Entity في Laravel: الأسباب والإصلاح خطوة بخطوة

شروحات تقنية

إذا ظهر لك رمز 422 Unprocessable Entity في Laravel فالسبب شبه المؤكد واحد: الطلب وصل إلى الخادم بشكل سليم، لكن بياناته رسبت في قواعد التحقق (Validation). أي أن حقلاً واحداً على الأقل لم يطابق ما تتوقعه القاعدة — حقل مطلوب وصل فارغاً، أو بريد بصيغة خاطئة، أو نص أُرسل مكان رقم. الحل لا يبدأ بتعديل الكود عشوائياً، بل بقراءة جسم الرد (Response Body) الذي يخبرك بالضبط أي حقل فشل ولماذا. في هذا الشرح نمشي معك من فهم الرمز حتى إصلاحه.

ما معنى الرمز 422 بالضبط؟

الرمز 422 من عائلة أخطاء العميل (4xx)، ومعناه الحرفي: "الخادم فهم الطلب وصيغته صحيحة، لكنه يرفض معالجته لأن محتواه غير صالح منطقياً". في Laravel لا يظهر هذا الرمز صدفة — إنه الرمز الافتراضي الذي يُرجعه الإطار تلقائياً عندما يفشل التحقق عبر $request->validate() أو FormRequest أو كائن Validator.

النقطة المهمة: 422 ليس خطأً في الخادم، ولا يعني أن الكود معطوب. إنه رسالة تقول لك "البيانات التي أرسلتها لا تطابق الشروط". لذلك تصحيحه غالباً يكون في جهة البيانات المُرسَلة أو في قاعدة التحقق نفسها، لا في منطق التطبيق.

متى يُرجع Laravel رمز 422 تحديداً؟

هنا مصدر التباس شائع: Laravel لا يُرجع 422 في كل الحالات. سلوكه يعتمد على نوع الطلب:

  • إذا كان الطلب يتوقع JSON (رأس Accept: application/json، أو طلب AJAX/API) فسيرجع رمز 422 مع كائن JSON يحوي الأخطاء.
  • إذا كان طلب متصفح عادي (نموذج HTML) فلن ترى 422 إطلاقاً؛ سيقوم Laravel بإعادة توجيه (redirect) بالرمز 302 إلى الصفحة السابقة مع تخزين الأخطاء في الجلسة لعرضها عبر $errors.

لذلك إذا كنت تبني API أو تستخدم axios/fetch ولا يظهر لك 422، فتأكد أولاً أنك ترسل رأس Accept: application/json. غياب هذا الرأس هو سبب رقم واحد لضياع رسائل الخطأ.

كيف تقرأ رسالة الخطأ لتحديد الحقل الفاشل

عند رمز 422 يكون جسم الرد بهذا الشكل الثابت:

{
  "message": "The given data was invalid.",
  "errors": {
    "email": ["حقل البريد الإلكتروني مطلوب."],
    "age": ["يجب أن يكون العمر رقماً صحيحاً."]
  }
}

مفتاح errors يحوي اسم كل حقل فشل ومعه سبب الفشل بالضبط. لا تخمّن — افتح تبويب Network في المتصفح أو اطبع error.response.data.errors في الواجهة، واقرأ هذا الكائن. هو خريطة الحل الكاملة.

خطوات إصلاح خطأ 422

  1. اقرأ مفتاح errors في جسم الرد وحدّد أسماء الحقول الفاشلة بدقة قبل أي تعديل.
  2. قارن أسماء الحقول: تأكد أن الاسم في الواجهة يطابق حرفياً الاسم في قاعدة التحقق. user_name وusername حقلان مختلفان تماماً، وهذا خطأ يتكرر كثيراً.
  3. تحقق من نوع البيانات: قاعدة integer ترفض النص "25" أحياناً حسب الإعداد، وقاعدة array ترفض القيمة المفردة. طابق النوع المُرسَل مع القاعدة.
  4. افحص الرؤوس (Headers): أرسل Content-Type: application/json عند إرسال جسم JSON، وAccept: application/json لتضمن رجوع 422 وليس 302.
  5. راجع القاعدة نفسها: قد تكون القاعدة أصرم من اللازم. مثال شائع: required على حقل اختياري فعلياً، أو unique يرفض تحديث السجل نفسه (استخدم Rule::unique(...)->ignore($id)).
  6. اضبط رسائل مخصّصة عبر messages() في FormRequest لتصل للمستخدم رسائل مفهومة بدل النص الافتراضي.
$validated = $request->validate([
    'email' => 'required|email',
    'name'  => 'required|string|max:255',
    'age'   => 'nullable|integer|min:1',
]);

422 مقابل أكواد الأخطاء المتشابهة

كثيرون يخلطون 422 بأكواد أخرى ويطاردون الحل في المكان الخطأ. هذا الجدول يوضح الفرق:

الرمزالمعنىالسبب الشائع في Laravel
422بيانات غير صالحةفشل قواعد التحقق (Validation)
419انتهت الجلسةرمز CSRF مفقود أو منتهٍ في النماذج
401غير مُصادَقمستخدم غير مسجّل الدخول / توكن غائب
403ممنوعصلاحية مرفوضة عبر Gate أو Policy
500خطأ خادماستثناء في الكود لا علاقة له بالمدخلات

إذا كان الرمز 419 وليس 422، فمشكلتك في CSRF لا في التحقق — لا تُضِع وقتك في قواعد validate().

خطأ شائع يقع فيه كثيرون

المقالات القديمة تنصح بتفعيل APP_DEBUG=true لرؤية تفاصيل خطأ 422 — وهذه نصيحة مضللة. رسائل التحقق تُرجَع في مفتاح errors سواء كان وضع التصحيح مفعّلاً أو مغلقاً، لأن 422 استجابة مقصودة لا استثناء غير متوقع. APP_DEBUG يؤثر فقط على أخطاء 500. بل يُنصح بإبقائه false في بيئة الإنتاج لأسباب أمنية. المكان الصحيح للبحث هو دائماً جسم الرد، لا سجلّ الأخطاء.

الأسئلة الشائعة

هل خطأ 422 يعني أن الخادم معطّل؟ لا. الخادم يعمل بشكل سليم؛ المشكلة في البيانات المُرسَلة التي لم تطابق شروط التحقق.

لماذا لا يظهر لي 422 بل يعيد توجيهي للصفحة السابقة؟ لأن طلبك يُعامَل كطلب متصفح عادي. أضف رأس Accept: application/json ليرجع Laravel رمز 422 مع الأخطاء بصيغة JSON.

كيف أعرض رسائل الخطأ في الواجهة الأمامية؟ في axios اقرأ error.response.data.errors، وهو كائن يربط كل اسم حقل بمصفوفة رسائله، فتعرضها تحت الحقل المناسب.

هل أستطيع تغيير الرمز 422 إلى رمز آخر؟ تقنياً نعم عبر معالجة الاستثناء ValidationException، لكن يُنصَح بإبقائه لأنه المعيار المتعارف عليه لأخطاء التحقق في REST APIs.