JSON object requested, multiple (or no) rows returned: إيش يعني؟

خطأ PGRST116 في Supabase مع Lovable و Bolt: ليش .single() يتعطّل لما يلقى صفر سطور أو أكثر من سطر، ومتى تستخدم .maybeSingle() ومتى تصلّح البيانات.

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

تفتح صفحة الحساب في منتجك، أو صفحة طلب معيّن، والصفحة تطلع فاضية أو تتعطّل. وفي Console تلقى خطأ فيه PGRST116 ومعه رسالة: JSON object requested, multiple (or no) rows returned، أو بصيغة أحدث: Cannot coerce the result to a single JSON object. الرسالتين لنفس الخطأ، والنص يختلف حسب الإصدار. نشوفه كثير في المنتجات المبنية بـ Lovable و Bolt و v0 و Cursor على Supabase، وسببه غالبًا كلمة وحدة في الكود: .single().

إيش يعني بالضبط

لما الكود يطلب بيانات من Supabase، الرد العادي قائمة: صفر سطور، أو سطر، أو مئة. .single() يقول لـ Supabase: «أبي سطر واحد بالضبط، ورجّعه لي كعنصر واحد مو قائمة». إذا الطلب لقى صفر سطور، أو سطرين وأكثر، Supabase ما يختار من عنده. يرفض الطلب ويرجع PGRST116 مع رمز الحالة 406. ونفس الشي في الحفظ والتعديل والحذف إذا الكود ينهي الطلب بـ .select().single()، وإذا تعديل لقى أكثر من سطر، يلغي التعديل كله.

الجزء اللي يفيدك هو details في نفس الرد. فيه عدد السطور اللي لقاها، مثل The result contains 0 rows أو The result contains 2 rows. هذا الرقم يحدد مشكلتك، لأن الصفر والاثنين لهم أسباب مختلفة تمامًا.

ليش يصير في المنتجات المبنية بالذكاء الاصطناعي

أدوات الذكاء الاصطناعي تحط .single() تقريبًا في كل مكان يجيب «شي واحد»: ملف المستخدم، إعداداته، طلب برقمه. في التجربة يمشي، لأن عندك حساب واحد وكل بياناته موجودة. الأسباب اللي نشوفها:

  • RLS يخفي السطر (صفر): RLS قواعد على الجدول تحدد مين يشوف أي سطور. لما القاعدة ما تسمح للمستخدم يشوف السطر، Supabase ما يرجع خطأ صلاحيات، يرجع كأن السطر مو موجود، فـ .single() يشوف صفر. ونفس الشي لو الطلب راح كزائر قبل ما تجهز جلسة المستخدم.
  • السطر فعلًا ناقص (صفر): مثلًا جدول profiles ينعبّى بـ trigger، وهو كود في قاعدة البيانات يشتغل لحاله لما يسجّل مستخدم جديد. المستخدمين اللي سجّلوا قبل ما ينضاف الـ trigger ما لهم سطر.
  • السطر انضاف مرتين (أكثر من سطر): الـ trigger يضيف سطر في profiles، وكود الواجهة بعد التسجيل يضيف سطر ثاني لنفس المستخدم. إذا عمود user_id ما عليه شرط يمنع التكرار، واسمه unique constraint، قاعدة البيانات تقبل الاثنين.
  • الفلتر واسع (أكثر من سطر): الكود يجيب «اشتراك المستخدم»، والمستخدم عنده اشتراك قديم وجديد.

كيف تتأكد بنفسك

  1. افتح منتجك، واضغط F12، وافتح تبويب Network، وسوّ الحركة اللي تفشل.
  2. دوّر على طلب رمزه 406 ورابطه فيه /rest/v1/ واسم الجدول. افتح Response واقرأ details: صفر ولا أكثر؟ إذا الكود يستخدم .maybeSingle() وفيه أكثر من سطر، الطلب يطلع 200 والخطأ يبان في Console فقط.
  3. من نفس الرابط خذ الفلتر، مثل user_id=eq. وبعده رقم المستخدم.
  4. في لوحة Supabase افتح Table Editor والجدول نفسه، وفلتر بنفس العمود ونفس الرقم. اللوحة تشوف كل السطور، لأنها ما تمر على RLS.

النتيجة تقول لك السبب:

  • سطرين أو أكثر: عندك تكرار.
  • سطر واحد، والمنتج يقول صفر: RLS يخفيه. تأكد بخيار عرض الجدول كمستخدم معيّن في Table Editor: اختار authenticated والمستخدم نفسه، وشوف هل يختفي السطر.
  • ما فيه شي: السطر فعلًا ناقص.

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

  • تبديل الدالة في كل مكان عشان الخطأ يختفي. .maybeSingle() بدل .single() يرجع null بدون خطأ لما ما فيه سطر، فيخفي مشكلة RLS أو السطر الناقص: الصفحة تفتح فاضية، والعميل يحسب بياناته انحذفت، وأنت ما يوصلك شي. وفي التكرار ما يفيد أصلًا، لأنه يرجع نفس الخطأ مع أكثر من سطر.
  • أخذ أول سطر وخلاص. إضافة .limit(1) قبل .single() تخفي الخطأ، والكود ياخذ واحد من السطرين وما تعرف أي واحد، والتكرار يبقى.
  • تعطيل RLS عشان السطر يبان. هذا يفتح الجدول لأي أحد، وشرحه في درس RLS.

الحل الصح

اختار الحل حسب الرقم في details:

  • صفر وهذا متوقع، مثل مستخدم ما أنشأ متجره بعد: هنا فقط استخدم .maybeSingle()، واعرض «ما عندك متجر للحين» مع الخطوة التالية. وتأكد من error قبل ما تلمس data، وإلا يطلع لك Cannot read properties of null.
  • صفر بسبب RLS: صلّح قاعدة SELECT عشان المستخدم يشوف سطره هو فقط. الطريقة في new row violates row-level security policy.
  • صفر لأن السطر ناقص: أضف السطور الناقصة للمستخدمين القدامى. وإذا الخطأ يقول إن الجدول نفسه مو موجود، هذا خطأ ثاني: relation does not exist.

وإذا لقى أكثر من سطر:

  1. قرّر مين يضيف السطر: الـ trigger أو الكود، مو الاثنين.
  2. احذف التكرار وخلّ سطر واحد لكل مستخدم.
  3. أضف unique constraint على user_id. بعده قاعدة البيانات نفسها ترفض أي تكرار، حتى لو رجعت الغلطة في الكود. لازم تحذف التكرار قبل، وإلا إضافة الشرط تفشل.
  4. إذا الكود يحتاج «أضف إذا مو موجود، وعدّل إذا موجود»، استخدم upsert مع onConflict: 'user_id'. upsert يعتمد على الشرط اللي أضفته، وبدونه يرجع خطأ.

تبي أحد يتأكد منها؟

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

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

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

ابدأ طلبك

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