Guides
Troubleshooting
Every error message we know of, quoted exactly, with what causes it and how to fix it. Search the page for the text you're seeing.
Tip: press ⌘ F (or Ctrl F) and paste your error. Headings below are the literal messages.
Scaffolding#
Invalid config: a new project needs at least a frontend or a backend#
You used the custom starter, its default, without choosing a stack. custom starts with no frontend and no backend. Either pick a named starter or choose one:
npx create-bsv-app@latest my-app --starter full-stack --yes
# or
npx create-bsv-app@latest my-app --starter custom --frontend react --backend express --yestarget directory is not empty: … new projects scaffold into an empty directory#
new mode only writes into an empty folder (a lone .git or bsv-scaffold.json is allowed). Pick a new folder name, or, to add capabilities to the project that's there, use add mode:
npx create-bsv-app@latest add --capabilities wallet-login --yesInvalid config: unknown starter: …#
Starter ids are lowercase and exact:
custom, react, express, full-stack, brc102-frontend, brc102-backend, pollr, meter, metamarket, todo, marscast, coinflip, postboard, locksmith, peerpay, atfinder
See Starters for what each one is.
Invalid config: unknown capability: …#
Valid ids are wallet-connect, wallet-login and signed-requests. Separate them with commas and no spaces: --capabilities wallet-login,signed-requests.
Invalid config: starter meter is a complete example and does not accept generated capabilities#
Complete examples are cloned as they are, so drop --capabilities. If you want capabilities, use a generated starter.
cannot infer separate client/server targets from a single package containing both react and express#
Add mode found one package.json with both React and Express, and can't guess where client and server files go. Pass a config with explicit targets: here's the exact file.
Invalid config: name is required#
A --file config needs "name", even in add mode.
Invalid config: --network must be main, test, or ttn#
The same pattern applies to --mode, --frontend, --backend and --package-manager: the message lists the allowed values. … requires a value means a flag is missing its argument, and unknown option: … means a typo. npx create-bsv-app --help prints every flag.
command failed (…): git clone …#
Complete-example starters are cloned with git. Install git, check that you can reach github.com, and run again into an empty folder.
The output says "cd client, npm install, npm run dev". Is that for me?#
No. That's create-vite's own message, printed halfway through. Follow the final Next: block, which says cd my-app and npm run dev. Dependencies are already installed.
It installed with npm but I use pnpm#
The CLI doesn't detect the package manager that launched it. Pass --package-manager pnpm (or yarn, or bun). In an existing project with a lockfile, installs follow the lockfile.
Odd failures on Node.js 20 or older#
create-bsv-app requires Node.js 22 or newer (npm may print an EBADENGINE warning). Check with node -v. Upgrade with nvm install 22, fnm install 22, or from nodejs.org. Older versions may half-work and then fail in confusing ways.
Build#
Client build fails with TS2304: Cannot find name 'requireIdentityKey'#
A known issue in create-bsv-app 1.1.2. The generated client has three type errors that npm run dev doesn't catch (Vite doesn't type-check) but npm run build does:
The second one is also a runtime bug: useWalletLogin().login() throws ReferenceError: requireIdentityKey is not defined. The demo login page doesn't use the hook, which is why the demo still works. Three one-line fixes:
import { getServerIdentity, readIdentityKeyResponse } from './serverIdentity.js'
import { getServerIdentity, readIdentityKeyResponse, requireIdentityKey } from './serverIdentity.js'import { getServerIdentity, readIdentityKeyResponse, requireIdentityKey } from './serverIdentity.js'
import { getServerIdentity, readIdentityKeyResponse } from './serverIdentity.js'async function readBoundedBody (response: Response): Promise<Uint8Array> {
async function readBoundedBody (response: Response): Promise<Uint8Array<ArrayBuffer>> {With those three changes, npm run build passes. We verified it on a fresh 1.1.2 full-stack scaffold.
Wallet & connection#
"No desktop wallet found" even though I installed one#
WalletClient('auto') looks for a wallet running on this machine. Make sure BSV Browser (opens in a new tab) is open and unlocked, then click Connect wallet again. Still nothing? Choose Connect with a mobile wallet and scan the QR code with BSV Browser on your phone.
failed to fetch server identity: … or TypeError: Failed to fetch#
The client can't reach the server, or CORS blocked it. Check in this order:
- Is the server running?
curl http://localhost:3000/healthshould print{"status":"ok"}. - Are you on exactly
http://localhost:5173? The server only allowsCLIENT_ORIGIN, which defaults tohttp://localhost:5173. Opening127.0.0.1:5173, or getting moved to:5174because 5173 was busy, is a different origin, and CORS blocks it. Free the port, or setCLIENT_ORIGINto match. - Is
VITE_API_URLright? Restartnpm run devafter changing.env. Vite reads it at startup.
The QR code never appears ("Generating code…")#
The mobile relay lives on the server (/api/session, /ws). Same checks as above. In production, make sure your host forwards WebSocket upgrades: see Deploy.
Login or signed request returns 401 {"error":"invalid proof"}#
The server rejected the proof. In order of likelihood:
- The server restarted between fetching its identity and receiving the proof. Without
SERVER_PRIVATE_KEYit gets a new identity on every start. Refresh the page, or set a key. actionorbodydiffer between client and server. They must match exactly. See capabilities.- The proof was reused or is stale. Each proof is single-use and expires after 2 minutes. Sign a fresh one per request.
- Your clock is off by more than 30 seconds. Sync your system time.
- The nonce store is full. The in-memory store holds 10,000 recent nonces and refuses new ones until they expire. Under sustained load, move it to Redis.
server returned another wallet identity#
The identity the server verified isn't the wallet you connected, usually because you switched accounts in the wallet mid-session. Reload and connect again.
API endpoint must be a safe absolute path#
apiFetch only accepts paths made of letters, numbers, /, _ and -. Query strings aren't allowed. Put parameters in the path (/api/notes/42), or in a POST body.
API request body must be a string#
apiFetch takes a string body. Wrap objects with JSON.stringify(...) and set content-type: application/json.
API response exceeds the byte limit#
apiFetch caps responses at 1 MiB and requests at 1 MiB, and times out after 10 seconds. Paginate large responses, or change the limits at the top of apiClient.ts if you really need to.
Production#
White screen in production, console says VITE_API_URL is required in production#
VITE_API_URL wasn't set when you ran vite build. It's baked in at build time. Rebuild with it set. It also has to be https://, or you'll see VITE_API_URL must be credential-free HTTPS (or exact HTTP localhost development).
SERVER_PRIVATE_KEY is required in production / CLIENT_ORIGIN is required in production#
Set them in the server's environment. See Deploy. CLIENT_ORIGIN must be a bare https:// origin: no path, no trailing slash, no credentials.
SERVER_PRIVATE_KEY must use its canonical encoding#
The key has to be in the exact format PrivateKey.toString() prints: lowercase hex. Uppercase hex or extra whitespace fail. Regenerate with the one-liner, or re-print your existing key through it.
PORT must be an integer from 1 to 65535#
PORT has to be a plain number with no leading zeros.
A refresh on /login returns 404#
Your static host needs a single-page-app fallback to index.html. Config for Vercel, Netlify and nginx.
Still stuck?#
- Read your project's
AGENTS.md. It documents every generated function. - Ask an assistant with the full docs: copy /llms-full.txt into it.
- Open an issue on bsv-blockchain/ts-stack (opens in a new tab) with your
bsv-scaffold.json, your Node version and the full error.