Troubleshooting

Common errors

Debug the version, runtime, remote sync, and cursor persistence issues that show up most often in the current integration flow.

Common failure modes

Most integration failures now cluster around version mismatch, runtime mismatch, or missing persistence on request-scoped hosts.

  • If nothing ever connects and there is no error at all, you imported clivly.config.ts but never called an entry point. The factory is pure — call start(), runScheduled(), or add clivlyVite(sdk).
  • If an enabled presence socket cannot connect, the SDK automatically returns to HTTP heartbeat and keeps retrying the socket. Check the host can make outbound wss:// connections; do not add a second heartbeat loop.
  • If generated imports or commands do not match the docs, run npx clivly --version — an older installed version is the usual cause.
  • If sync stops after the first serverless request, move from start() to runScheduled() or createClivlyHandler().
  • If every cold start re-reads the entire dataset, add a persistent cursorStore.
  • If an entity syncs nothing with no error, source was keyed by your entity key instead of a CRM concept. It must be contacts / companies / deals / custom.
  • If rows sync on insert but never on edit, the cursor column does not change when a row is updated. Add an updated_at column and use it as cursorField.
  • If status reports "Field mapping dry run … missing mapped column(s): name → full_name", you are on clivly@0.7.3 or earlier, where fromDrizzle keyed rows by Drizzle property names instead of column names. Upgrade.
  • If every sync fails with "The host app returned 403" while clivly dev is running, Vite is refusing the tunnel's Host header. Add server: { allowedHosts: [".trycloudflare.com"] } to your Vite config. This affects every Vite-based framework — SvelteKit, TanStack Start, Remix and Nuxt — but not Next.js. Open the failure's "What your app replied" disclosure to see Vite's own wording.
  • If the dashboard still says "No schema discovered yet" after pairing, start your app and let it serve one request. Clivly discovers your tables from the SDK's heartbeat, so nothing is reported until the app runs. push-schema does not fix this — it sends object types and mappings, never the table list — and status is read-only by design.
  • If a config change appears to do nothing, restart your app — it reads clivly.config.ts once, at boot.
  • If credentials are written but the app never loads them, check the env file: Next.js reads .env.local, wrangler reads .dev.vars and nothing else.
  • If remote sync stops after rotating secrets, redeploy the host with the new CLIVLY_SYNC_TRIGGER_SECRET.
  • If a TanStack Start route 404s, it must use createFileRoute from @tanstack/react-router and export as Route — the older createAPIFileRoute form is skipped by the route generator.
  • If the widget 403s, check the widget record's allowed origins — exact-match, so https://example.com does not cover https://www.example.com.
  • If the browser bundle throws on node:fs or node:child_process, something imported the clivly package root instead of clivly/sdk.

For the fast debug checklist and how to read clivly status, see Diagnostics.