<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: fixkit ai</title>
    <description>The latest articles on DEV Community by fixkit ai (@fixkitai).</description>
    <link>https://dev.to/fixkitai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4192993%2Fc90b492e-a78f-4652-b338-12b7d6ae78b9.png</url>
      <title>DEV Community: fixkit ai</title>
      <link>https://dev.to/fixkitai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fixkitai"/>
    <language>en</language>
    <item>
      <title>"Invalid API key" or undefined env vars on Vercel: how to fix it</title>
      <dc:creator>fixkit ai</dc:creator>
      <pubDate>Sun, 18 Oct 2026 23:52:10 +0000</pubDate>
      <link>https://dev.to/fixkitai/invalid-api-key-or-undefined-env-vars-on-vercel-how-to-fix-it-50ig</link>
      <guid>https://dev.to/fixkitai/invalid-api-key-or-undefined-env-vars-on-vercel-how-to-fix-it-50ig</guid>
      <description>&lt;p&gt;Your app works on your machine. You deploy to Vercel and get one of these:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: supabaseUrl is required.
AuthApiError: Invalid API key
OpenAI API error: 401 Incorrect API key provided: undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or &lt;code&gt;process.env.MY_KEY&lt;/code&gt; is simply &lt;code&gt;undefined&lt;/code&gt; in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happens
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env.local&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; deployed (it's git-ignored, as it should be). Vercel needs its own copy.&lt;/li&gt;
&lt;li&gt;The variable was added after the last deployment. Env vars only apply to &lt;strong&gt;new&lt;/strong&gt; deployments.&lt;/li&gt;
&lt;li&gt;It was added for the wrong environment (Production vs Preview vs Development).&lt;/li&gt;
&lt;li&gt;It's used in browser code without the &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; prefix (Next.js) or &lt;code&gt;VITE_&lt;/code&gt; prefix (Vite).&lt;/li&gt;
&lt;li&gt;Typos, quotes, or trailing spaces/newlines were pasted into the value.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fix 1: add the variables in Vercel, then redeploy
&lt;/h2&gt;

&lt;p&gt;Vercel â†’ Project â†’ Settings â†’ Environment Variables. Add each key, tick the environments that need it, then &lt;strong&gt;redeploy&lt;/strong&gt; (Deployments â†’ â‹¯ â†’ Redeploy). Or use the CLI:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel env add NEXT_PUBLIC_SUPABASE_URL production
vercel env pull .env.local   # pulls Development values (add --environment=production for prod)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Fix 2: use the right prefix for browser code
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Next.js: inlined at BUILD time, visible in the browser
const url = process.env.NEXT_PUBLIC_SUPABASE_URL!;

// Vite
const url = import.meta.env.VITE_SUPABASE_URL;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Public prefixes are baked in at build time, which is another reason a redeploy is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3: keep secrets server-side
&lt;/h2&gt;

&lt;p&gt;Secret keys (&lt;code&gt;SUPABASE_SERVICE_ROLE_KEY&lt;/code&gt;, &lt;code&gt;OPENAI_API_KEY&lt;/code&gt;, &lt;code&gt;STRIPE_SECRET_KEY&lt;/code&gt;) must &lt;strong&gt;not&lt;/strong&gt; get a public prefix. Anything with &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; or &lt;code&gt;VITE_&lt;/code&gt; ends up in the JavaScript sent to every visitor. Use secrets only in Route Handlers, Server Actions or API routes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// app/api/chat/route.ts
export async function POST(req: Request) {
  const key = process.env.OPENAI_API_KEY; // server only
  // ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Fix 4: fail fast with a clear message
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function requireEnv(name: string) {
  const v = process.env[name];
  if (!v) throw new Error(`Missing env var: ${name}`);
  return v;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; variables in client code, reference them literally (&lt;code&gt;process.env.NEXT_PUBLIC_X&lt;/code&gt;). Dynamic lookups like &lt;code&gt;process.env[name]&lt;/code&gt; aren't inlined in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 5: check the value itself
&lt;/h2&gt;

&lt;p&gt;Re-copy the key from the provider dashboard. Remove quotes and trailing spaces. Make sure it's the key for the right project (for example, the Supabase anon or &lt;code&gt;sb_publishable_â€¦&lt;/code&gt; key in the client, never the service role or &lt;code&gt;sb_secret_â€¦&lt;/code&gt; key).&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I added it but it's still undefined.&lt;/strong&gt; Did you redeploy? Is it ticked for Production?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the Supabase anon key safe to expose?&lt;/strong&gt; It's designed to be public, but only if Row Level Security is enabled on your tables.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://fixkit-ai.netlify.app/guides/vercel-env-vars-invalid-api-key.html" rel="noopener noreferrer"&gt;FixKit AI&lt;/a&gt;. Deploy failing for a different reason? See &lt;a href="https://fixkit-ai.netlify.app/guides/v0-bolt-vercel-deploy-failed.html" rel="noopener noreferrer"&gt;why v0/Bolt apps fail on Vercel&lt;/a&gt;, or paste the error into the free &lt;a href="https://fixkit-ai.netlify.app/products/error-fixer.html" rel="noopener noreferrer"&gt;FixKit Error Fixer&lt;/a&gt; (disclosure: I built it).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Supabase RLS errors in Lovable and Bolt apps (and how to fix them safely)</title>
      <dc:creator>fixkit ai</dc:creator>
      <pubDate>Sun, 18 Oct 2026 23:52:01 +0000</pubDate>
      <link>https://dev.to/fixkitai/supabase-rls-errors-in-lovable-and-bolt-apps-and-how-to-fix-them-safely-2kkb</link>
      <guid>https://dev.to/fixkitai/supabase-rls-errors-in-lovable-and-bolt-apps-and-how-to-fix-them-safely-2kkb</guid>
      <description>&lt;p&gt;If you built your app with Lovable or Bolt on top of Supabase, sooner or later you'll see this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new row violates row-level security policy for table "todos"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's Postgres error code &lt;code&gt;42501&lt;/code&gt;. Its quieter cousin is worse: a &lt;code&gt;select&lt;/code&gt; that returns &lt;code&gt;[]&lt;/code&gt; with &lt;strong&gt;no error&lt;/strong&gt;, even though the table clearly has rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happens
&lt;/h2&gt;

&lt;p&gt;When Row Level Security (RLS) is enabled and no policy allows an action, Supabase blocks it. Common causes in AI-built apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RLS is enabled but no &lt;code&gt;insert&lt;/code&gt;/&lt;code&gt;select&lt;/code&gt; policy exists&lt;/li&gt;
&lt;li&gt;The user isn't logged in, so &lt;code&gt;auth.uid()&lt;/code&gt; is null&lt;/li&gt;
&lt;li&gt;The insert doesn't set &lt;code&gt;user_id&lt;/code&gt;, or sets it to a different value&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;update&lt;/code&gt; policy is missing its &lt;code&gt;with check&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reads and writes fail differently. A blocked &lt;code&gt;select&lt;/code&gt; doesn't throw; rows are filtered out and you get &lt;code&gt;[]&lt;/code&gt;. A blocked &lt;code&gt;insert&lt;/code&gt; throws the error above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1: add owner-based policies
&lt;/h2&gt;

&lt;p&gt;Run this in the Supabase SQL editor (rename &lt;code&gt;todos&lt;/code&gt; to your table):&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alter table public.todos enable row level security;

&lt;p&gt;create policy "Users read own todos" on public.todos&lt;br&gt;
  for select to authenticated using ((select auth.uid()) = user_id);&lt;/p&gt;

&lt;p&gt;create policy "Users insert own todos" on public.todos&lt;br&gt;
  for insert to authenticated with check ((select auth.uid()) = user_id);&lt;/p&gt;

&lt;p&gt;create policy "Users update own todos" on public.todos&lt;br&gt;
  for update to authenticated&lt;br&gt;
  using ((select auth.uid()) = user_id) with check ((select auth.uid()) = user_id);&lt;/p&gt;

&lt;p&gt;create policy "Users delete own todos" on public.todos&lt;br&gt;
  for delete to authenticated using ((select auth.uid()) = user_id);&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Fix 2: fill in &lt;code&gt;user_id&lt;/code&gt; automatically&lt;br&gt;
&lt;/h2&gt;
&lt;br&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alter table public.todos alter column user_id set default auth.uid();&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Fix 3: make sure the user is actually signed in&lt;br&gt;
&lt;/h2&gt;
&lt;br&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { data: { user } } = await supabase.auth.getUser();&lt;br&gt;
if (!user) throw new Error('Not signed in');&lt;br&gt;
await supabase.from('todos').insert({ title, user_id: user.id });&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Don't "fix" it by disabling RLS or shipping the service_role key&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;service_role&lt;/code&gt; key (and the newer &lt;code&gt;sb_secret_...&lt;/code&gt; keys) bypasses RLS entirely. Keep it on the server only, never in frontend code. The browser should only use the anon or publishable key, and that key is only safe because RLS limits what it can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt to paste into Lovable or Bolt
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Write Supabase RLS policies so authenticated users can only select, insert, update, and delete rows where user_id = auth.uid(). Don't disable RLS and don't use the service_role key in the client.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why do I get empty results instead of an error?&lt;/strong&gt; RLS filters &lt;code&gt;select&lt;/code&gt; results silently. With no policy, you get zero rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a public read policy OK?&lt;/strong&gt; Yes, for genuinely public data: &lt;code&gt;for select to anon, authenticated using (true)&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://fixkit-ai.netlify.app/guides/supabase-rls-errors-lovable-bolt.html" rel="noopener noreferrer"&gt;FixKit AI&lt;/a&gt;. If you're seeing a different error, paste it into the free &lt;a href="https://fixkit-ai.netlify.app/products/error-fixer.html" rel="noopener noreferrer"&gt;FixKit Error Fixer&lt;/a&gt; (disclosure: I built it). Related: &lt;a href="https://fixkit-ai.netlify.app/guides/cors-error-lovable-api.html" rel="noopener noreferrer"&gt;CORS errors when a Lovable app calls an API&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
