Troubleshooting
The most common problems you'll hit building with the Fayz SDK — each one in a problem → cause → fix format. Start with the blank screen: it's by far the number one question from newcomers.
npm run dev opens a placeholder screen / empty anchor
Problem. You generated the app, ran npm install && npm run dev, opened the browser and saw a bare-bones screen — a placeholder, an empty anchor, none of the admin shell the docs promise.
Cause. This is expected. The runtime that assembles the shell from your app.manifest.json ships with the Fayz platform, not in the public @fayz-ai/sdk package the scaffold installs today. The project you generated has the right manifest, plugins and config — but running locally against the public SDK, it doesn't yet have the app-runtime that renders any of it. The blank screen isn't a bug: it's the boundary between what's already public and what runs inside Fayz.
Fix. There's no "fix" — it's a property of the current stage. What to do instead:
- Treat the generated app as the source of truth for config: the manifest, the wired plugins and the file tree are already real and valid.
- To see the app rendered today, run it inside the Fayz platform.
- Understand why this boundary exists before spending time hunting for the "error".
This is the most common point of confusion for anyone trying the public SDK for the first time. Read The two paths to understand who owns the shell, and step 02 of the tutorial to see what each scaffold file does. The blank screen makes sense once you've read both.
Blank screen / useAuth must be used inside <AuthProvider>
Problem. You build an app in code against the published packages, start the dev server, and the screen goes blank. In the console: useAuth must be used inside <AuthProvider> — even though AuthProvider clearly wraps the tree.
Cause. A version conflict producing two copies of the React auth context. Concretely, on the 0.6.x line: @fayz-ai/saas@0.6.0 depends on plugin-auth ^0.1.0; npm resolves that to 0.1.3, which in turn requires auth/core ^0.7.1. The result is a second copy of @fayz-ai/auth in the node_modules tree. The AuthProvider from one copy and the useAuth from the other reference different React context objects — so as far as useAuth is concerned there's no provider above it, and it throws. The blank screen is that exception taking down the render.
Fix. Force a single version line across the whole auth axis with an overrides block in your app's package.json, pinned to the same line as the saas version you're on:
{
"overrides": {
"@fayz-ai/plugin-auth": "0.1.3",
"@fayz-ai/auth": "0.7.1",
"@fayz-ai/core": "0.6.0",
"@fayz-ai/ui": "0.6.0"
}
}
Then delete node_modules and the lockfile and reinstall (rm -rf node_modules package-lock.json && npm install) so overrides actually collapses the two copies into one. Adjust the numbers to match your @fayz-ai/saas version — the point is that plugin-auth, auth, core and ui all land on a coherent line, with no second copy of the context.
fayz doctor warns about plugins referenced in the manifest
Problem. You run fayz doctor and see a warning like:
⚠ manifest references plugin(s) [agenda, crm] — each id must resolve to an installed @fayz-ai/plugin-* factory wired in src/plugins.generated.ts or src/config/app.tsx 0 error(s), 1 warning(s)
Cause. This is a warning, not an error — note the 0 error(s). Every plugin id in the manifest has to resolve to a @fayz-ai/plugin-* factory that is actually installed (via npm) and wired into src/plugins.generated.ts or src/config/app.tsx. In the real model, a plugin is an installed npm package plus an entry in the plugins array — not something the runtime injects on its own. doctor lists the ids that aren't wired yet so you know what's left to install or connect.
Fix. Install the package for each referenced plugin (npm i @fayz-ai/plugin-agenda, …) and confirm it's wired into src/plugins.generated.ts or src/config/app.tsx. It's a warning, not an error — the 0 error(s) count means the build won't break and CI won't fail; but each listed id only becomes a loaded plugin once it's installed and wired.
fayz doctor rejects a custom theme in a code-first app
Problem. You have a code-first app — the real theme lives in the code-config (a SaasTheme with custom HSL values, perfectly valid) and app.manifest.json is vestigial. fayz doctor still rejects the manifest because theme.brand isn't one of the seven known brand names.
Cause. Today doctor validates the manifest strictly, with no notion that in a code-first app the manifest is just a leftover and the code-config is the source of truth for the theme. The manifest's theme.brand only accepts the seven built-in brand names; a valid custom HSL in your SaasTheme doesn't satisfy that check because the check never looks at the code-config.
Fix. Keep a minimal, valid theme.brand in the vestigial manifest — any of the seven brand names — purely to pass doctor, while the real theme stays in the code-config, which is what actually paints the app:
{ "theme": { "brand": "violet" } }
The brand named here doesn't affect the rendered app (the code-config wins); it just keeps the manifest valid. It's an honest workaround, not a mistake on your side. Validation will become path-aware — recognizing code-first apps and letting the code-config be the theme's source of truth — in an upcoming SDK fix; until then, the named brand in the manifest is the bridge.
fayz db apply complains about missing environment variables
Problem.
✗ Missing required Supabase credentials: SUPABASE_PROJECT_REF (or SUPABASE_REF), SUPABASE_PAT (or SUPABASE_ACCESS_TOKEN).
Cause. fayz db apply talks to the Supabase management API and never assumes default credentials. It needs two things: which project (SUPABASE_PROJECT_REF, or the alias SUPABASE_REF) and with which token (SUPABASE_PAT, or the alias SUPABASE_ACCESS_TOKEN).
Fix. Set both in your shell or in <app>/.env.local (which is git-ignored):
SUPABASE_PROJECT_REF=your-project-ref SUPABASE_PAT=sbp_...
Where to find each one:
- Access token (PAT): Supabase dashboard → Account → Access Tokens → Generate new token.
- Project ref: Supabase dashboard → Project Settings → General (it's also the subdomain in your project URL).
The dry run says "ships no migrations"
Problem. fayz db apply --dry-run prints a note:
installed @fayz-ai/db ships no migrations/ — the spine step is empty (upgrade to @fayz-ai/db >= 0.1.3 once published)
Cause. The migration "spine" (the shared base schema) ships inside the @fayz-ai/db package. The version published today (0.1.2) doesn't bundle those .sql files yet — which is why the spine step comes out empty in the plan. The spine SQL lands in 0.1.3.
Fix. This is expected until 0.1.3 ships. --dry-run still shows the plan correctly (including your own migrations); only the spine step is empty. Once 0.1.3+ is published, npm install @fayz-ai/db@latest fills that step in automatically. See the Changelog.
db apply refuses to run in a non-interactive shell
Problem.
✗ Refusing to apply migrations without confirmation in a non-interactive shell. Re-run with --yes to proceed.
Cause. Applying migrations is a destructive operation against a real database, so the command asks for a y confirmation. In a shell without a TTY (CI, a pipe, an AI agent) there's no way to type it — so the command refuses rather than hanging on stdin that will never arrive.
Fix. Pass --yes (or -y) to skip the prompt explicitly:
fayz db apply --yes
--yes applies migrations without asking for confirmation. Use it in deliberate automation, not as a habit in your local terminal.
See also: Connect your agent — how an agent runs fayz commands with AGENTS.md in context.
fayz create rejects the app name
Problem.
✗ Provide a kebab-case app name, e.g. fayz create admin my-app
Cause. The app name has to be kebab-case: lowercase letters, numbers and hyphens only, starting with a letter or number. Names with uppercase letters, spaces, _ or special characters (My Store, my_store, MyStore) are rejected.
Fix. Use a valid slug:
fayz create admin my-store
Port 5173 is already in use
Problem. When you run npm run dev, Vite either fails or starts on a different port because 5173 is taken.
Cause. The scaffold uses Vite, whose dev server binds to port 5173 by default. Another process (a previous instance that didn't die, another Vite app) is already holding the port.
Fix. Pick one:
- Free the port by killing the old process:
lsof -ti:5173 | xargs kill
- Or run on a different port:
npm run dev -- --port 5174