Skip to content

.eq() filter returns empty results on Vercel Serverless Functions #2120

@the-fixr

Description

@the-fixr

Bug Report

Describe the bug

Single-column .eq() filters on certain tables silently return empty arrays when running inside Vercel Serverless Functions. The exact same query works correctly via the Supabase REST API (curl) and in local development (next dev).

To Reproduce

Table schema:

CREATE TABLE check_ins (
  id BIGSERIAL PRIMARY KEY,
  epoch_day INTEGER NOT NULL,
  wallet TEXT NOT NULL,
  weight INTEGER NOT NULL DEFAULT 1,
  checked_in_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(epoch_day, wallet)
);
CREATE INDEX idx_checkins_wallet ON check_ins(wallet);
ALTER TABLE check_ins ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Public read check_ins" ON check_ins FOR SELECT USING (true);

Code that fails on Vercel (returns empty data):

const { data, error } = await supabase
  .from('check_ins')
  .select('epoch_day, weight, wallet')
  .eq('wallet', walletAddress);
// data = [] on Vercel, correct results locally and via REST API

Same query via REST API works:

curl "https://<project>.supabase.co/rest/v1/check_ins?wallet=eq.<wallet>&select=epoch_day,weight,wallet" \
  -H "apikey: <service_key>" -H "Authorization: Bearer <service_key>"
# Returns correct rows

Workaround that works everywhere:

const { data: all } = await supabase
  .from('check_ins')
  .select('epoch_day, weight, wallet')
  .limit(10000);
const rows = (all || []).filter((r) => r.wallet === walletAddress);

Additional observations

  1. .eq() with a second filter works fine: .eq('epoch_day', X).eq('wallet', wallet) returns correct results. The issue only appears when .eq('wallet', wallet) is the sole filter.

  2. .in().gt() chained filters also fail: .in('epoch_day', [...]).gt('total_weight', 0) returns empty despite matching rows existing. Splitting into .in() only and filtering .gt() in JS resolves it.

  3. .select('*', { count: 'exact', head: true }) with .eq() also returns 0 despite rows existing.

  4. .select().limit(N) without any .eq() filter returns correct results, confirming the data is accessible.

  5. The same client instance (service role key, same createClient call) works for .eq() on other tables.

  6. Issue reproduces with both anon key and service_role key.

  7. RLS is enabled with a permissive FOR SELECT USING (true) policy.

Expected behavior

.eq('wallet', walletAddress) should return the same rows as the equivalent REST API query.

Environment

  • @supabase/supabase-js: ^2.49.1
  • Runtime: Vercel Serverless Functions (Node.js 22.x)
  • Framework: Next.js 14 (App Router, force-dynamic)
  • Supabase: Hosted (free tier)
  • Region: US East

Possible causes

  • PostgREST query planner behaving differently with single-filter vs multi-filter queries
  • Connection pooling or stale schema cache in serverless cold starts
  • RLS policy evaluation interacting with the query in unexpected ways
  • supabase-js query builder serializing the filter differently than expected

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs more infoNeeds more information from the OP. If no info is provided, it will be marked as stale and closed.postgrest-jsRelated to the postgrest-js library.repro neededIssue is missing a reproduction example.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions