Your AI agent checked its queue, found nothing, and went back to sleep. The queue was full. Elevare Digital's autonomous AI system ARIA silently failed to process jobs because a Postgres Row-Level Security policy filtered out all rows for the orchestrator's connection without raising an error. The orchestrator polled the work queue, received an empty result set, and idled while jobs piled up. The issue was caused by a missing service-role bypass in the RLS policy, which was added for user-facing queue visibility but inadvertently blocked the service account. Postgres Row-Level Security doesn't raise an error when it blocks you. It returns zero rows. Your query succeeds. Your agent sees an empty queue. Your agent idles. Your jobs pile up. This is what happened to ARIA, our autonomous AI system at Elevare Digital. SELECT — a blocked read and a genuinely empty table look identical to the callerThe orchestrator polls a work queue table. Normal operation: The logs showed healthy idle heartbeats. Monitoring showed the agent alive and polling. From the outside, everything looked fine. Jobs were not being processed. Someone added a Row-Level Security policy to the queue table, scoped to auth.uid . Correct for user-facing reads. But the orchestrator connects under the service role — and no service-role bypass was added to the policy. Here's the policy as it was written: -- Added for user-facing queue visibility CREATE POLICY "users see own jobs" ON work queue FOR SELECT USING auth.uid = user id ; And RLS was enabled on the table: ALTER TABLE work queue ENABLE ROW LEVEL SECURITY; No bypass for the service role. No FOR ALL escape. The orchestrator's SELECT now matched zero rows — because RLS filtered every row out before returning results. Postgres does not raise. It does not warn. The query completes with status 200 and an empty array. // Orchestrator poll — looks completely normal const { data: jobs, error } = await supabase .from 'work queue' .select ' ' .eq 'status', 'pending' ; // error is null. jobs is . Agent concludes: nothing to do. if jobs || jobs.length === 0 { await recordIdleHeartbeat ; return; } The error is null. The jobs array is empty. The agent's logic is correct for the data it received. The data it received was wrong in a way that produced no signal. If RLS blocks a write, you often get an error — the row you tried to insert violates a policy, or returns nothing when you expected a rowcount. Writes are easier to notice. SELECT under RLS is different. The design intent is that users should not be able to distinguish "this row doesn't exist" from "this row exists but you can't see it." That's a security feature. It's also exactly the wrong behavior for an orchestrator that needs to know the difference between "queue is empty" and "I am blind." The service role in Supabase bypasses RLS by default — but only if you're using the service-role key on the client. If your edge function or backend is using the anon key, or if it's operating in a context where auth.uid resolves to null, RLS applies and silently filters. -- This is what the orchestrator needed, but wasn't there CREATE POLICY "service role bypass" ON work queue FOR ALL USING auth.role = 'service role' ; -- Or, simpler: grant the service role explicit bypass at the table level ALTER TABLE work queue FORCE ROW LEVEL SECURITY; -- applies to all -- and then in your Supabase client: use the service-role key, which bypasses RLS automatically The actual bypass mechanism in Supabase is that the service-role JWT includes "role": "service role" , and Supabase's Postgres config grants that role BYPASSRLS . If your client is initialized with the service-role key, you're fine. If it's not, RLS applies — no error, just silence. The real repair has two parts: fix the RLS policy, and add a check that will catch this failure mode again. Part 1 — Fix the policy: -- Preserve user-facing policy CREATE POLICY "users see own jobs" ON work queue FOR SELECT USING auth.uid = user id ; -- Add explicit service-role access -- Or: initialize your orchestrator client with the service-role key, -- which bypasses RLS automatically via BYPASSRLS grant CREATE POLICY "orchestrator full access" ON work queue FOR ALL USING auth.role = 'service role' WITH CHECK auth.role = 'service role' ; Part 2 — The canary check: The orchestrator now runs a canary query before trusting an empty result. The canary queries a row it knows exists — a sentinel row inserted specifically for this purpose, or a count from an unrestricted table the orchestrator owns. async function pollQueue { const { data: jobs, error: queueError } = await supabase .from 'work queue' .select ' ' .eq 'status', 'pending' ; if queueError { await alertOpsChannel 'queue poll error', queueError ; return; } // Jobs came back — process normally if jobs && jobs.length 0 { await processJobs jobs ; return; } // Empty result — but is it genuinely empty, or are we blind? const canaryOk = await verifyReadAccess ; if canaryOk { // This is the case we were missing before await alertOpsChannel 'queue read access lost', { message: 'Orchestrator received empty queue result but canary check failed. Possible RLS or permission regression.', } ; return; // Do NOT record idle heartbeat — we don't know the real state } // Canary passed — empty really means empty await recordIdleHeartbeat ; } async function verifyReadAccess : Promise