EN
ابدأ هنا المواضيع الفِرَق المرجع المستجدّات المحفوظات
سير العمل والاحتراف

قراءة الأخطاء والـ stack traces

الخطأ ليس عقابًا ولا حكمًا عليك. إنه آلة تكون حرفيّة تمامًا بشأن الموضع الذي علقت فيه — وهذه الحرفيّة هي سبب كون المشكلة قابلة للإصلاح أصلًا.

قراءة 8 دقائق · حُدّث في 2026-08-16
قراءة الأخطاء والـ stack traces

للجميع ردّ الفعل الأول نفسه، وهو لا يتحسّن كثيرًا مع الخبرة: تزيغ العينان، وتهبط المعدة، وتشتدّ الرغبة في إغلاق النافذة. عشرون سطرًا باللون الأحمر، نصفها يسمّي ملفات لم تسمع بها قط، وينتهي كله بشيء مثل TypeError: Cannot read properties of undefined (reading 'map').

ويستحقّ الأمر أن يُقال صراحةً، لأنه سبب وجود هذه الصفحة: كل من يستسلم في العمل مع الكود تقريبًا يستسلم أثناء خطأ. الجدار الأحمر يُقرَأ كحكم — على المشروع، وقليلًا عليك أنت. وهو ليس كذلك. إنه آلة تكون حرفيّة إلى أقصى حدّ بشأن النقطة الدقيقة التي علقت عندها، وهذه الحرفيّة تحديدًا هي ما يجعل المشكلة قابلة للحلّ.

ما الموجود هناك فعلًا

الـ stack trace هو قائمة استدعاءات الـ functions التي كانت جارية لحظة فشل شيء ما. يبدو عدائيًا لأنه صيغ لآلة — مسارات ملفات كاملة، وأرقام أسطر، وأسماء functions، وأحيانًا أعداد — لكن انزع ذلك عنه ولن يخبرك سوى ثلاثة أشياء:

  • رسالة الخطأما الذي حدث، في سطر واحد.
  • ملف ورقم سطرأين حدث.
  • سلسلة الاستدعاءات التي أوصلت إليهكيف وصل البرنامج إلى ذلك الموضع.

هذه هي المفردات كلها. كل trace ستراه في حياتك، بأيّ لغة، هو هذه الأشياء الثلاثة مرتديةً علامات ترقيم مختلفة.

وثمّة أمر صغير يستحقّ أن تعرفه، لأنه الموضع الذي تخطئ فيه النصائح الواثقة عادةً: ترتيب تلك السلسلة ليس ثابتًا بين اللغات. Python تطبع أعمق استدعاء أخيرًا، فأسفل الـ traceback في Python هو موضع العطب. أما JavaScript وNode فتطبعان أعمق استدعاء أولًا، فالأعلى هو الموضع. ولـ Java وRuby وGo وغيرها كلٌّ عرفها الخاص.

ولهذا بالضبط تأتي النصيحة أدناه على ما هي عليه. لا يمكنك أن تعرف بثقة أيّ طرف من الـ trace هو المهمّ دون أن تعرف مسبقًا عُرف اللغة — فلا تحاول أن تختار.

الحركة

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

تظهر لي رسالة الخطأ هذه. ماذا تعني وأين أبحث؟

[الصق الـ trace كاملًا هنا]

I'm getting this error. What does it mean and where do I look?

[paste the full trace here]

ما يعود إليك هو الرسالة بلغة بسيطة، وإشارة إلى الملف والسطر اللذين سبّباها فعلًا، ونظرة في ذلك الملف عادةً، ثم إمّا إصلاح وإمّا الشيء التالي الذي تفحصه. النصّ المخيف يصير فقرة.

لا تقتطعه

هذا هو الخطأ الوحيد الذي يستحقّ أن يُسمّى، لأنه شبه شامل ولأنه يبدو نقيض الخطأ. يلصق الناس السطر الأخير وحده — أو السطر الذي يبدو ذا معنى — بحجّة أنهم يزيلون الضوضاء ويدخلون في صلب الموضوع.

ما يزيلونه في الحقيقة هو سلسلة السببية. السطر الذي يظهر فيه الخطأ ليس في الغالب السطر الذي نشأ فيه: شيء ما سُلّم قيمة سيئة قبل أربعة استدعاءات ولم يشتكِ أحد حتى استُخدمت. اقطع السلسلة وتكون قد حذفت الجزء الذي يفسّر كيف انتهى سطر بريء المظهر تمامًا إلى الفشل.

الصق الشيء كاملًا. لا تُدلِ برأيك، ولا تنتقِ مسبقًا السطر الذي تظنّه المهمّ — اختيار الجزء ذي الصلة هو العمل التشخيصي نفسه، وهو الجزء الذي تحاول أن تحصل على مساعدة فيه.

وإن كان المُخرَج قد مرّ خارج الشاشة، مرّر إلى الأعلى وخذ الكتلة من أول سطر فارغ فوقه حتى آخر سطر أحمر.

أخطاء لا تأتي مع trace

كثير منها كذلك. ستحصل على سطر واحد مقتضب في log — command not found، port 3000 already in use — أو اختبار فاشل يعرض المتوقَّع مقابل الفعلي، أو خطّ متعرّج مع تلميح، أو مجرّد مربّع أحمر في صفحة كان يُفترض أن يحدث فيها شيء.

تعامل معها كلها بالطريقة نفسها: انسخ النصّ، وأضف ما كنت تفعله حين ظهر.

طلبت منك أن تشغّل هذا المشروع فحصلت على هذا. ما الخطأ؟

[الصق المُخرَج]

I asked you to start this project and got this. What's wrong?

[paste the output]

ضع ذلك إلى جانب «لا يعمل» ويصير الفرق بديهيًا. وكل من حاول أن يساعد قريبًا له في مشكلة حاسوبه عبر الرسائل النصّية يفهم هذا فهمًا عميقًا وشخصيًا.

حين يشير إلى كود شخص آخر

هذه هي اللحظة التي تجعل الناس يستسلمون، وهي مبنيّة على سوء فهم يستحقّ التفكيك مباشرةً.

الـ trace يشير إلى مكان لم تطأه قط — داخليات framework، أو package لم تثبّته عن قصد، أو أحشاء runtime اللغة. والاستنتاج الذي يبدو معقولًا: أنا لا أعرف هذا الكود، فلا يمكن أن أصلح هذا.

أنت لست مضطرًّا إلى ذلك في الغالب الأعمّ. الخطأ الذي يُطلَق داخل كود شخص آخر يكون سببه دائمًا تقريبًا أن كودك أنت استخدمه بطريقة لم يتوقّعها.

بشكل ملموس: لنفترض أن ملفًا يقول require('./emial') بينما ينبغي أن يقول require('./email'). تشغيل المشروع ينفجر بجدار أحمر ينتهي بـ Error: Cannot find module './emial'، مُطلَقًا من عمق module loader في Node — ملف لم تفتحه قط ولا شأن لك بفتحه. الصق الجدار، فيكون الجواب:

«هذا يُطلَق من نظام require في Node، لكن سببه server/index.js:4 — كتبت require('./emial') ولا وجود لملف بهذا الاسم. قصدت ./email

خطأ إملائي واحد، في ملفك أنت، في سطر كتبته أنت. الـ library كانت تعمل تمامًا طوال الوقت. هذا هو شكل الغالبية الساحقة من الأخطاء المخيفة المظهر، واستيعاب ذلك هو معظم ما يفصل بين من يجد التصحيح محتمَلًا ومن لا يجده كذلك.

إعادة التأطير التي تستحقّ أن تبقى

الأخطاء ليست عقابًا، وليست إشارة إلى أنك تخوض فوق طاقتك. إنها أدقّ تغذية راجعة ستحصل عليها من حاسوب على الإطلاق — آلة تخبرك، بدقّة تامّة وبلا أيّ لباقة، بالنقطة المضبوطة التي كفّت عندها تعليماتها عن أن تكون ذات معنى.

وسبب كون ذلك عزاءً باردًا فيما مضى أن الدقّة كانت مشفّرة في صيغة كُتبت للآلة لا لك. هذا هو الجزء الذي تغيّر. الدقّة كانت نافعة دائمًا؛ صارت الآن مقروءة أيضًا.

وبعد عدد كافٍ من هذه، يكفّ الجدار الأحمر عن أن يُقرَأ كجدار ويبدأ أن يُقرَأ كباب. باب مهيب أحيانًا. لكنه باب.

ومتى كان الكود غير معطوب بل غير مألوف فحسب، تكون الحركة المرافقة هي التتبّع — تتبّع قيمة إلى الوراء نحو مصدرها، أو إلى الأمام نحو كل ما يعتمد عليها.

المواضيع

أسئلة يطرحها الناس

ظهر للتوّ خمسة عشر سطرًا باللون الأحمر. ماذا ألصق؟
الخمسة عشر كلها، مع جملة واحدة عمّا كنت تفعله حين حدث ذلك. لا السطر الأخير، ولا مسار الملف الذي تظنّه ذا صلة، ولا لقطة شاشة لجزء منه. الكتلة كاملةً والسياق. الاقتطاع يبدو تعاونًا وهو أشيع طريقة يجعل بها الناس تشخيص الخطأ أصعب ممّا كان يحتاج أن يكون.
الخطأ داخل library لم أفتحها في حياتي. هل المشكلة مشكلتي؟
شبه مؤكّد نعم، وهذا هو الخبر الجيّد. الخطأ الذي *يُطلَق* في عمق framework أو في داخليات اللغة يكون *سببه* عادةً أن كودك أنت سلّمها شيئًا لم تتوقّعه — اسم ملف مكتوب خطأ، أو قيمة كانت فارغة، أو إعداد غير موجود. الإصلاح عادةً سطر واحد في ملف تملكه أنت، لا في أيّ مكان داخل الـ library. من حقّك أن تشعر بالارتياح.
وماذا لو لم يكن هناك stack trace أصلًا — مجرّد سطر قصير غامض؟
عامله بالطريقة نفسها تمامًا: انسخ النصّ *ومعه* ما كنت تفعله. `command not found`، و`port 3000 already in use`، والفرق بين المتوقَّع والفعلي في اختبار فاشل، ومربّع أحمر في صفحة — كلها قابلة للتشخيص، وكلها تصير أسهل بفارق كبير حين تُرفق بجملة واحدة من السياق. السياق هو المضاعِف، لا طول الخطأ.
هل أقرأ الـ trace بنفسي أولًا، أم أسلّمه مباشرةً؟
سلّمه، ثم اقرأ الشرح الذي يعود إليك — هذا هو الترتيب الذي يعلّمك شيئًا فعلًا. ستلتقط شكل الـ traces أسرع بكثير بقراءة عشرين ترجمة بلغة بسيطة لأخطاء حقيقية واجهتها، مقارنةً بدراسة الصيغة في المجرّد. الهدف ليس أن تستغني تمامًا عن المساعدة في قراءتها؛ الهدف أن يكفّ الجدار الأحمر عن كونه مخيفًا.
طبِّقها عمليًا
تصفَّح المواضيع
ابدأ