Troubleshooting
This page collects the spots people most often stop at. Find the entry that matches what you are seeing and follow the notes underneath. If your symptom is not on the list, copy the error message verbatim into Claude Code and ask “how do I fix this?” — a next thing to try usually comes back.
Stuck during environment setup
Section titled “Stuck during environment setup”Node will not install
Section titled “Node will not install”Usually nvm install 20 froze midway or failed outright.
On macOS and Linux, open a fresh terminal and run command -v nvm. If the output is empty, nvm itself installed but the loader did not make it into your shell startup file (.zshrc or .bashrc). Paste the two lines the nvm install printout suggested (export NVM_DIR="$HOME/.nvm" ...) into that file by hand and open a new terminal.
On Windows, double-check that you actually finished the WSL2 install. The commands in this guide do not run in PowerShell — every step belongs inside the Ubuntu shell on WSL2.
node --version prints something older than v20
Section titled “node --version prints something older than v20”Multiple Node versions are installed and the system default points at an older one.
nvm use 20nvm alias default 20Open a new terminal and run node --version again to confirm.
pnpm install fails on a permission error
Section titled “pnpm install fails on a permission error”If you see EACCES or permission denied, the npm global install location’s permissions are the most likely cause. Try these in order:
- Do not retry with
sudo. That tends to compound the problem. - If
node_modules/is leftover from a previous attempt, delete it and try again:rm -rf node_modules pnpm-lock.yaml. - If the error sticks, reinstall the nvm copy of Node:
nvm uninstall 20 && nvm install 20.
Docker is not running, so supabase start fails
Section titled “Docker is not running, so supabase start fails”You see Cannot connect to the Docker daemon or something close. On macOS and Windows, check Docker Desktop is actually running. The whale icon in the system tray should not be gray — it has to show the running state.
On Linux, docker ps sometimes hits a permission error. Confirm you ran the usermod -aG docker $USER line in 01-prerequisites.md and logged out and back in afterwards.
Stuck on env variables
Section titled “Stuck on env variables”A build error like Missing environment variable VITE_SUPABASE_URL
Section titled “A build error like Missing environment variable VITE_SUPABASE_URL”The zod validation in src/shared/config/env.ts caught it. Usually one of three things:
.env.localdoes not exist — start withcp .env.example .env.local.- The file exists but the
VITE_SUPABASE_URL=line is empty — re-copy from Settings → API on the Supabase dashboard. - The prefix is not
VITE_(e.g. onlySUPABASE_URL=...is in the file) — prependVITE_so the variable reaches the client bundle.
After editing env, restart pnpm dev — Vite reads .env.local once at dev server boot.
STRIPE_SECRET_KEY prints undefined in the browser console
Section titled “STRIPE_SECRET_KEY prints undefined in the browser console”That key has no VITE_ prefix, so it does not get exposed to the client. That is expected. The Stripe Secret key is read inside an Edge Function via Deno.env.get('STRIPE_SECRET_KEY'), and the value lives under supabase secrets set.
supabase secrets listIf STRIPE_SECRET_KEY is not in the listing, set it:
supabase secrets set STRIPE_SECRET_KEY=sk_test_...Stuck on Supabase
Section titled “Stuck on Supabase”Signup does not go through
Section titled “Signup does not go through”First check that VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in .env.local are not malformed. The URL must look like https://<ref>.supabase.co, with no trailing /.
If the values are clean, head to Authentication → Providers on the Supabase dashboard and confirm Email is enabled. Sometimes it gets locked down to “not accepting signups.”
Open DevTools, go to the Network tab, and click signup. Look at the response body of the request to supabase.co. The reason for the rejection is in there.
Data does not land in Supabase
Section titled “Data does not land in Supabase”Open Table Editor and confirm your domain table actually exists. The SQL migration may not have been applied.
supabase db pushIf the table exists but no data lands, it is the RLS policy seat. The default is deny, so without a policy even INSERT is blocked. Head to Authentication → Policies and look at the policy list for that table. If empty, add the policy inside api/migrations/ and re-run supabase db push.
Do not create policies in the UI. Policies created in the UI do not end up in git, so they disappear in the next environment.
401 or 403 errors
Section titled “401 or 403 errors”Re-copy the anon key. A trailing space or newline often sneaks in during paste. Never use the service_role key inside the client. It bypasses RLS, so once it lands on the client every row is exposed.
Stuck on Stripe checkout
Section titled “Stuck on Stripe checkout”Stripe webhook signature verification fails
Section titled “Stripe webhook signature verification fails”Webhook signature verification failed shows up in Edge Function logs. Almost always one of three:
STRIPE_WEBHOOK_SECRETis not set insupabase secrets. Confirm withsupabase secrets list, then set:supabase secrets set STRIPE_WEBHOOK_SECRET=whsec_....- The secret is set but it belongs to a different endpoint. On the Stripe dashboard, Developers → Webhooks, click your endpoint — the Signing secret is right there. Copy it again.
- For local development with
stripe listen, the signing secret it prints (whsec_...) differs from the one on the dashboard. Locally, set the valuestripe listenprinted.
The Checkout screen flashes and closes
Section titled “The Checkout screen flashes and closes”The Price ID in pricing-grid is still a placeholder when you click the checkout button. The Price ID in src/widgets/pricing-grid/model/plans.ts has to be your own test-mode Price ID from the Stripe dashboard.
You find it on the Stripe dashboard under Products — click Pro or Enterprise, and the price_... Price ID sits next to the price.
FSD lint blocks the build
Section titled “FSD lint blocks the build”Cross-feature import not allowed
Section titled “Cross-feature import not allowed”You imported features/sign-in from inside features/checkout. FSD’s six-layer rule forbids direct cross-slice imports within the same layer.
If two features share logic, pull it down into shared/lib/ or entities/. Or compose the two features one layer up in a widget (e.g. widgets/auth-checkout-flow/).
cannot import from internal path
Section titled “cannot import from internal path”You imported features/checkout/model/useCheckout.ts directly from another slice. FSD only allows the slice’s index.ts (public API) to be imported from outside.
// blockedimport { useCheckout } from '@/features/checkout/model/useCheckout';
// allowed — only what index.ts exportsimport { useCheckout } from '@/features/checkout';jsx-a11y/alt-text lint error
Section titled “jsx-a11y/alt-text lint error”An <img> is missing the alt attribute. For decorative images, an empty string is correct.
// Meaningful image<img src="/logo.svg" alt="MyApp logo" />
// Decorative image (screen readers skip it)<img src="/decoration.svg" alt="" />Stuck on build and dev server
Section titled “Stuck on build and dev server”Port 5173 is already in use
Section titled “Port 5173 is already in use”Port 5173 is in use, trying another one... drops. A previous dev server did not shut down.
lsof -ti:5173 | xargs killKill the process holding the port, then bring pnpm dev back up. Vite often picks a different port (5174 and so on) on its own — using that URL also works.
The screen does not reflect a code change
Section titled “The screen does not reflect a code change”Usually the dev server is dead. Look at the terminal and confirm pnpm dev is still alive. If it is alive and the screen still does not update, it is browser cache — force-refresh (Cmd+Shift+R or Ctrl+Shift+R).
Edits to CSS seats like tokens.css occasionally slip past HMR. Cycling the dev server (Ctrl+C and bring it back) clears it.
pnpm build fails on a type error
Section titled “pnpm build fails on a type error”src/features/checkout/model/useCheckout.ts(14,7): error TS2322: Type 'string' is not assignable to type 'PriceId'.This shape of error means a type mismatch in code the AI wrote. Paste the output verbatim into Claude Code and say “fix this” — the AI patches the seat.
If you attempt a commit while the build is broken, the pre-commit-check.sh hook blocks it. That is by design. The hook is what keeps broken code out of your git history.
Anything else
Section titled “Anything else”If nothing here matches, two more things to try.
First, copy the entire error message into Claude Code and ask “how do I fix this?”. A next move usually comes back, and it is often a good one.
If that still does not unstick it, open a GitHub issue or post in your team’s Slack. Include the same three things together:
- Where you got stuck (which file, which command)
- The full error message
- Environment info (macOS / Linux / Windows, Node version, Docker version, Supabase CLI version)