# Troubleshooting your website

> Every error message the SDK and API give a website, and every common symptom with pages, previews, cache refresh, types, SEO and regions, with the cause and the fix.

Source: https://docs.bifrostorbit.com/cms/developers/troubleshooting/

Find the message or symptom, then the cause and fix. **Configuration › API playground** is the quickest way to see what the API answers for a given address, region and key.

## Error messages

### From the client

| Message | Cause | Fix |
| --- | --- | --- |
| `A baseUrl is required` | `CMS_API_URL` is not set where the code runs, including during `next build` | Set it in `.env.local` and in your hosting, for builds and for running |
| `An apiKey is required` | `CMS_PUBLIC_KEY` is not set, or `lib/cms.ts` was imported into browser code, where server settings are empty | Set it. Add `import 'server-only'` to `lib/cms.ts` so browser imports fail at build time with a clear message. |
| `A secret CMS key must never be used in browser code. Use a public cms_pk_ key here.` | A `cms_sk_` key reached a client created in the browser | Create clients with secret keys only in server code. In the browser, use a public key. |
| `Previewing needs a previewKey on the client` | A call with `preview: true`, but the client has no `previewKey` | Set `CMS_PREVIEW_KEY` on the website that shows previews. On the live website, do not pass `preview: true`; draft mode is never on there unless someone opened a preview link. |
| `Pass the CMS client, or set CMS_API_URL` | `CmsBridge` or `createPreviewHandler` was used without `client`, and `CMS_API_URL` is not set | Pass `client={cms}` or `{ client: cms }` |
| `The webhook secret is required` | `createRevalidateHandler` was created without a secret, often at build time | Set `CMS_WEBHOOK_SECRET`, or create the handler inside the route as in step 15 of [Connect a website](https://docs.bifrostorbit.com/cms/developers/connect-a-website/) |

### From the API

The client turns error answers into these errors, all with `status`, `code` and `message`:

| Error | Status | Common causes | Fix |
| --- | --- | --- | --- |
| `CmsAuthError` | 401 | The key is mistyped, revoked or expired. A public key asked for drafts. A secret key was sent from a browser. The key may not read the region or language asked for. | Check the key in **Configuration › API keys**: its environment, regions, languages and expiry. Create a new one if in doubt. |
| `CmsNotFoundError` | 404 | `getPage`: nothing published at that address in that region. `getGlobal` or `getNavigation`: no entry or menu with that key. Any call: the region or language does not exist. | Use `find…` or `resolve` where missing is normal. Check the key, region and language in the playground. |
| `CmsRateLimitError` | 429 | More than 15,000 requests a minute from one key or IP address. `retryAfter` says how many seconds to wait. | Cache as in [Caching and refreshing pages](https://docs.bifrostorbit.com/cms/developers/caching-and-refresh/). Slow down scripts and build loops. |
| `CmsUnavailableError` | 5xx or none | `The CMS could not be reached`, `The CMS did not answer within 5000ms`, or `The CMS returned 503`, after the retries | Usually brief. Cached pages keep being served. See "When the CMS cannot be reached" in [Deploy your website](https://docs.bifrostorbit.com/cms/developers/deploy-your-website/). |
| `CmsError` | 400 | `code: "bad_request"`: an unknown `sort` value, a filter key with characters other than letters, digits and underscores, or an `include` other than `fields` or `references` | Fix the call. The message says which part is wrong. |

All of them extend `CmsError`, so `error instanceof CmsError` catches every API error:

```ts
import { CmsAuthError, CmsError, CmsNotFoundError, CmsRateLimitError, CmsUnavailableError } from '@bifrost-orbit-cms/sdk'

try {
  await cms.getPage('/about')
} catch (error) {
  if (error instanceof CmsNotFoundError) notFound()
  if (error instanceof CmsRateLimitError) console.warn(`Retry in ${error.retryAfter}s`)
  throw error
}
```

### From the preview route

| Answer | Cause | Fix |
| --- | --- | --- |
| `400 A preview token is required` | The address has neither `?token=` nor `?preview=` | Open previews from the editor |
| `401 That preview link is invalid or has expired` | The token is more than an hour old, was made for another space, or was cut short when copied | Reopen the page in the editor, which makes a new token |

### From the webhook route

| Answer | Cause | Fix |
| --- | --- | --- |
| `401 Bad signature` | `CMS_WEBHOOK_SECRET` is wrong or incomplete, or something changed the body on the way | Copy the whole secret, including `whsec_`. Make sure no proxy rewrites the body. |
| `401 The message is too old` | Your server's clock is more than five minutes out | Sync the clock with NTP |
| `503` with `not_configured` | Your route answers this while `CMS_WEBHOOK_SECRET` is not set | Set it and redeploy |
| `404` or `405` | The webhook's address is wrong, or the route has no `POST` | Check the path and that the file is `app/api/revalidate/route.ts` exporting `POST` |
| `307`, `308` | The address redirects, for example to `www` or to add a slash | Register the final address |

### From the type generator

| Message | Cause | Fix |
| --- | --- | --- |
| `Set CMS_API_URL and CMS_PUBLIC_KEY, or pass --url and --key.` | The settings were not loaded. npm scripts do not read `.env.local` by themselves. | Use `node --env-file-if-exists=.env.local` as in step 7 of the tutorial, or pass `--url` and `--key` |
| `The CMS answered 401 for …/schema` | The key is wrong, revoked or expired | Check it in **Configuration › API keys** |
| `The CMS answered 404 for …/schema` | The address is wrong | Use `https://api.bifrostorbit.com/cms` |
| `Usage: cms-orbit generate …` | The command was run without `generate` | `npx cms-orbit generate --out cms/types.ts` |

### In development

| Message | Cause | Fix |
| --- | --- | --- |
| A dashed box: `No renderer registered for "…"` | The page has a component that is not in the registry. Production renders nothing in its place. | Add it to the registry. If it is new, regenerate the types first. |
| `You're importing a component that needs "server-only"` | A client component imports `lib/cms.ts`, directly or through another file | Fetch in a server component and pass the data down as props |
| `Functions cannot be passed directly to Client Components` | The registry was passed as a prop from a server component to a client component | Import the registry inside the client file, as `components/live-page.tsx` does |
| `async/await is not yet supported in Client Components` | An async block component is drawn by `CmsLivePage`, which runs in the browser | Fetch its data in the page route and pass it down; see "Components that need more data" in [Render components](https://docs.bifrostorbit.com/cms/developers/render-blocks/) |
| `Invalid src prop … hostname "…" is not configured` | `next/image` with an image host not in `remotePatterns` | Add the host from the image's `url` to `images.remotePatterns` |

### TypeScript

| Error | Cause | Fix |
| --- | --- | --- |
| `Property 'hero' is missing in type …` on `defineRegistry` | A component in the generated types has no entry | Add it, or point it at `() => null` if it never appears on pages |
| `Property 'heading' does not exist on type …`, or every field is `unknown` | The generated types are not loaded | Keep `import '@/cms/types'` in `cms/registry.tsx`, and check `tsconfig.json` includes the file |
| A field that exists in the CMS is missing from the type | The types are out of date | `npm run cms:types` |
| `Type 'string' is not assignable to type 'CmsEntry<…>'` | Types were generated with `--include references`, but the page was read without `include: ['references']`, or the other way round | Use both or neither |

## Symptoms

### Pages

| What you see | Likely cause | Fix |
| --- | --- | --- |
| Every page is the 404 page | The region does not match, or nothing is published in the environment the key belongs to | Check `CMS_DEFAULT_REGION` and the key's environment. Try the address in the playground with the same key. |
| One page is 404, but it exists in the CMS | It is published in another region or environment, or only saved as a draft. Or the path has a trailing slash or a region prefix. | Publish it in the right place. Pass the address as the CMS stores it: `/services`, not `/services/` or `/de/services`. |
| A page shows the wrong language | No `locale` was passed, so the region's default answered, or a fallback answered | Pass `locale`. Check `page.meta.fallbackApplied`. Use `strict: true` to refuse fallbacks. |
| A component is missing, with no message | It is not in the registry, in production | Add it |
| A link does not appear | It points at a page that is not published, so `href` is `null` | Publish the page, or render the label without a link |
| Menu items are missing | They link to pages not published in this region and language, or are hidden | Publish the pages, or check the menu in **Menus** |
| A list is empty | The content type key is wrong, the entries are in another language (lists do not fall back), or they are global entries, which lists leave out | Check `type`, `locale` and the content type |
| References arrive as ids | The call has no `include: ['references']` | Add it |
| An image has no `srcset` | `sizes` was not passed to `CmsImage`, or the image address has no `/uploads/` | Pass `sizes` |
| Rich text shows as HTML tags | It was rendered as text | Use `RichText` |

### Previews

| What you see | Likely cause | Fix |
| --- | --- | --- |
| The preview area is blank or refuses to connect | Your website sends `X-Frame-Options` or a `frame-ancestors` that does not allow `https://app.bifrostorbit.com`, or the Preview URL is wrong or not `https` | See "Let the editor show your website" in [Deploy your website](https://docs.bifrostorbit.com/cms/developers/deploy-your-website/). Check **Preview URL** in the space's **Settings**. |
| The preview shows the published page, not the draft | `proxy.ts` is missing, so `?preview=` is ignored. Or the page route does not pass `preview` from `draftMode()`. Or the website has no preview key. | Add the proxy and preview route from step 14 of the tutorial |
| The preview shows the draft in a new tab, but not inside the editor | The draft mode cookie is blocked inside the frame: the website runs with `next dev`, is not `https`, or the browser blocks cookies in frames from other websites, as Safari does by default | Test with `next build` and `next start` or a deployed website, use `https`, or use **Open in a new tab** |
| The preview only changes after saving | The page is drawn with `CmsPage`, not `CmsLivePage` | Use `PageBody` and `LivePage` from step 14 |
| The header or title does not change as editors type | Only the page body is live. Everything else changes when the preview reloads after saving. | Expected |
| Clicking a block does not select it | The component has no `data-cms-id={block.id}` on its outer element, or the bridge is not loaded | Add the attribute. Check `<CmsBridge client={cms} />` is in the layout. |
| Clicking selects the parent block | The nested block you draw yourself has no `data-cms-id` | Add `data-cms-id={node.id}` |
| A page in another region previews the default region | The Preview URL has no region prefix | Add each region under **Other preview URLs** and choose it above the preview; see [Regions and languages](https://docs.bifrostorbit.com/cms/developers/regions-and-languages/) |
| Visitors see drafts | Impossible unless they have the draft mode cookie, which only the preview route sets after the CMS accepts a token | Check that the live website has no preview key, and that your own code does not pass `preview: true` |

### Publishing and cache

| What you see | Likely cause | Fix |
| --- | --- | --- |
| Changes take up to a minute or more to appear | No webhook, or it fails | Create one and check **Deliveries** |
| The webhook answers 200 but the page does not change | The client has no `cache: { tags: true }`. Or the region you read with is a short code, or not set, so the tag does not match. Or a CDN holds the old HTML. | See "Make sure the tags match" in [Caching and refreshing pages](https://docs.bifrostorbit.com/cms/developers/caching-and-refresh/) |
| Some copies of the website are fresh and others are not | Several servers, each with its own cache | Use a shared cache handler, or one server |
| Nothing is ever cached and the CMS gets a request for every view | `cache` is missing on the client, or the layout or page reads `cookies()` or `headers()` for every request, which renders on each request | Set `cache.revalidate`. CMS answers stay cached even when the page renders per request. |
| Everything refreshes on every publish | Pages changed address, a shared section was published, or messages arrive without a region | Expected for those changes |
| **Deliveries** shows nothing | The webhook is off, for another environment, or the event is not ticked | See [Refresh the website when content changes](https://docs.bifrostorbit.com/cms/developers/webhooks/) |

### SEO

| What you see | Likely cause | Fix |
| --- | --- | --- |
| The site name appears twice in titles | Your layout sets `title.template`, and the CMS title already has the template from **SEO › Settings** | Remove the layout's template |
| Canonical links or the sitemap use the wrong domain | **Configuration › Domains** has no primary domain for the environment, or the wrong one | Add and verify the domain, and make it primary |
| The sitemap is empty | No domain is set up, every page is no-index or left out of the sitemap, or the key is from another environment | Check the domains and the pages' SEO settings |
| robots.txt says `Disallow: /` on the live website | The website uses a key from a non-indexable environment, such as Staging | Use a key from Production |
| No hreflang links | The page exists in one language only, or `toMetadata` is not used | Expected for one language; otherwise use `toMetadata` |
| Next.js complains about both `robots.ts` and `robots.txt/route.ts` | Both exist | Keep one |

### Builds and types

| What you see | Likely cause | Fix |
| --- | --- | --- |
| The build fails with `A baseUrl is required` | The settings are not available at build time | Add them to the build environment |
| The build is slow and makes many CMS requests | `generateStaticParams` returns pages | Return `[]` and let pages build on first visit |
| CI fails at `git diff --exit-code cms/types.ts` | Someone changed the schema and the committed types are out of date | Run `npm run cms:types` and commit |

Still stuck? Try the same request in **Configuration › API playground** with the same key, region and language as your website. If the playground answers as expected, the problem is in the website; if not, it is in the content or the key.
