# Errors

> Every error the CLI and the generated code can throw, grouped by where it comes from, with what it means and what to do.

> Agents: search these docs with the `search_docs` tool on the MCP server at https://createbsvapp.vercel.app/mcp, or read everything at https://createbsvapp.vercel.app/llms-full.txt.

The generated helpers throw plain `Error`s with a fixed message. There are no custom error classes, so match on the message. For step-by-step fixes, see [Troubleshooting](https://createbsvapp.vercel.app/docs/troubleshooting).

```ts twoslash
import { useWalletLogin } from './bsv/useWalletLogin'
declare const login: ReturnType<typeof useWalletLogin>['login']
// ---cut---
try {
  await login()
} catch (err) {
  const message = err instanceof Error ? err.message : String(err)
  if (message.startsWith('login failed:')) {
    // the server answered 401: sign again, or check the server's identity
  } else if (message.startsWith('API ')) {
    // network or response limits: see the apiClient.ts table below
  } else throw err
}
```

## CLI {#cli}

Config problems are prefixed `Invalid config:` and exit with code `1`.

| Message | Meaning |
| --- | --- |
| `a new project needs at least a frontend or a backend` | `custom` starter with no stack. Pick `full-stack`, or pass `--frontend` and/or `--backend` |
| `target directory is not empty: …` | `new` mode only writes into an empty folder. Use another folder or [add mode](https://createbsvapp.vercel.app/docs/add-to-existing) |
| `unknown starter: …` / `unknown capability: …` | typo in an id. See [Starters](https://createbsvapp.vercel.app/docs/starters) and [Capabilities](https://createbsvapp.vercel.app/docs/capabilities) |
| `starter … is a complete example and does not accept generated capabilities` | drop `--capabilities` for complete examples |
| `cannot infer separate client/server targets from a single package containing both react and express; use --file with explicit targets` | [use `--file` with `targets`](https://createbsvapp.vercel.app/docs/add-to-existing#how-the-cli-finds-your-app) |
| `name is required` | a `--file` config needs `"name"` |
| `--network must be main, test, or ttn` (and the same for `--mode`, `--frontend`, `--backend`, `--package-manager`) | invalid flag value |
| `… requires a value` / `unknown option: …` / `unexpected argument: …` | flag syntax. `--help` lists every flag |
| `config file not found: …` / `cannot read config file: …` / `invalid JSON in …` | the `--file` path or contents |
| `targets.client must be a safe relative path` / `invalid bsvDir: …` | no absolute paths, no `..` |
| `command failed (…): …` | a step such as `git clone` or `npm install` failed. Its own output is just above |

## apiClient.ts {#apiclientts}

Thrown by `apiFetch` and `readApiJson` in the browser.

| Message | Meaning |
| --- | --- |
| <a id="api-endpoint-must-be-a-safe-absolute-path"></a>`API endpoint must be a safe absolute path` | the path has a query string, `..`, or characters outside `A-Z a-z 0-9 / _ -` |
| `API request body must be a string` | pass `JSON.stringify(...)` |
| `API request exceeds the byte limit` | request body over 1 MiB |
| `API response exceeds the byte limit` | response over 1 MiB. Paginate |
| `API response has an invalid Content-Length` / `API response length does not match Content-Length` | a broken proxy or server |
| `API response changed network authority` | the response came from another origin (redirects are refused) |
| `API response is not valid UTF-8` / `API response is not valid JSON` | `readApiJson` couldn't parse it |
| `AbortError` | no complete response within 10 seconds |

## Identity and login {#identity}

| Message | From | Meaning |
| --- | --- | --- |
| `failed to fetch server identity: <status>` | `getServerIdentity` | `GET /api/identity` didn't return 2xx. Is the server up? |
| `server returned an invalid identity response` | `serverIdentity.ts` | the response wasn't exactly `{ identityKey }` |
| `server returned an invalid identity key` | `serverIdentity.ts` | not a valid compressed public key |
| `connect a wallet first (initializeWallet / relay)` | `useWalletLogin` | `login()` called with no wallet |
| `connect a wallet first` | `useSignedRequest` | `signedFetch()` called with no wallet |
| `login failed: <status>` | `useWalletLogin` | the server rejected the proof |
| `server returned another wallet identity` | login | the verified key isn't the connected wallet's |
| `No authenticated desktop wallet found` | `walletAcquisition.ts` | caught internally; the UI moves to *No desktop wallet found* |
| `useWallet must be used within WalletProvider` | `WalletContext.tsx` | wrap your app in `<WalletProviders>` |
| `useWalletConnection must be used within WalletConnectionProvider` | `WalletConnectionContext.tsx` | same |

## Server responses {#server-responses}

| Status | Body | Meaning |
| --- | --- | --- |
| `401` | `{ "error": "invalid proof" }` | the proof failed: [why](https://createbsvapp.vercel.app/docs/api-server#fails-when) |
| `400` | from `express.json` | malformed JSON, or a body over 64 kB |

## Client config {#client-config}

Thrown when the client bundle loads, which shows as a blank page.

- `VITE_API_URL is required in production`
- `VITE_API_URL must be credential-free HTTPS (or exact HTTP localhost development)`
- `VITE_BSV_NETWORK must be main, test, or ttn`

## Server config {#server-config}

Thrown at startup.

- `SERVER_PRIVATE_KEY is required in production`
- `SERVER_PRIVATE_KEY must use its canonical encoding`
- `CLIENT_ORIGIN is required in production`
- `CLIENT_ORIGIN must be credential-free HTTPS (or exact HTTP localhost development) origin`
- `PORT must be an integer from 1 to 65535`
- `BSV_NETWORK must be main, test, or ttn`
- `JWT_SECRET must contain at least 32 bytes` (only if you add the [session pattern](https://createbsvapp.vercel.app/docs/capabilities#turning-login-into-a-session))
