Troubleshooting
Concrete symptoms and fixes for the issues you're most likely to hit when running Tours. Each entry follows a problem → cause → fix shape: match the symptom, confirm the cause, apply the fix, and check the relevant logs if it persists.
Symptom Index
| Symptom | Likely cause | Section |
|---|---|---|
| Can't reach / connect to the database | Wrong DATABASE_URL or no SSL |
Database |
| "relation does not exist" / missing tables | Schema not provisioned | Database |
| Install Wizard never appears | DATABASE_URL already set or already installed |
Install Wizard |
| Public License Banner / admin License Gate showing | Domain not activated or grace lapsed | Licensing |
| Premium add-on shows as locked | No entitlement and no purchase code | Licensing |
Uploads fail (SignatureDoesNotMatch) |
Wrong storage secret key | Storage |
| Images upload but don't display | Wrong public base URL | Storage |
| Emails not arriving | SMTP not configured/active | |
| A route 404s despite existing | Stale dev route table (Turbopack) | Dev Server |
| Build fails on deploy | Node version or missing env var | Build & Env |
| App reads as "unlicensed" after moving domains | License bound to the old domain | Licensing |
Database
Can't reach the database
- Cause: an incorrect
DATABASE_URL, a missing SSL parameter, or the database refusing connections from your host. Tours connects to PostgreSQL through@neondatabase/serverless. - Fix:
- Verify the
DATABASE_URLhost, user, password, and database name. - Append
?sslmode=requirefor Neon and most managed Postgres providers. - Confirm the database accepts connections from your host/IP.
- For app runtime on Neon, use the pooler host; for
pg_dump/pg_restore, use the direct (unpooled) host.
- Verify the
DATABASE_URL="postgresql://user:pass@host/db?sslmode=require&channel_binding=require"
Missing tables / "relation does not exist"
- Cause: you imported a partial database or skipped the wizard, so an
ensure*Schema()provisioning step hasn't run for that table. - Fix: re-open
/installand complete the Database step, which (re)creates the required tables idempotently. The schema is self-healing — tables are created on demand — so completing the Database step against your database resolves this.
Install Wizard
The wizard at /install doesn't appear (redirects away)
- Cause: the installer gate keys off
DATABASE_URLand an installed lock. IfDATABASE_URLis already present, the app treats the database as configured and may skip past early steps; if installation already completed,/installis closed. - Fix: to re-run from scratch, point the app at a fresh database and clear the install lock, then reload
/install.
The wizard can't save my settings on Vercel
- Cause: Vercel's filesystem is read-only, so the wizard cannot write a
.envfile. - Fix: on read-only hosts the installer surfaces the values (such as
DATABASE_URLand a generatedJWT_SECRET) for you to add as Vercel project environment variables manually, then redeploy. The database schema is still created over the serverless connection.
Licensing
Public License Banner or admin License Gate is showing
- Cause: the installation isn't in an active licensed state. Common reasons and their fixes:
| Reason | Fix |
|---|---|
| Unactivated | Enter your purchase code in the Install Wizard's License step or in Admin → License. |
| Grace lapsed | The license server was unreachable; run Admin → License → Recheck once connectivity is restored. |
| Domain mismatch | The purchase code is active on another domain — deactivate it there to release the seat, then activate here. |
| Dev host | localhost, *.localhost, *.test, and private LAN ranges never require a license and never show the banner. |
You can inspect the public, non-secret state at GET /api/license/status (returns state, type, entitlements, and a message — no purchase code or domain).
A premium add-on shows as locked
- Cause: the add-on is neither covered by a license entitlement nor activated with a per-add-on purchase code — or it's unlocked but the admin toggle hasn't been switched on.
- Fix:
- Confirm the entitlement is present in Admin → License (or
GET /api/license/status): a match is*/all, the channel id, or the exact<channel>:<provider>key. - Or activate the add-on's purchase code in Admin → Add-ons.
- Remember the two-gate model: unlocking only makes the add-on available — you still flip the admin toggle to switch it on.
- Free providers (
email:smtp,analytics:ga4,payments:cod/bank/paypal,storage:r2,video:youtube/vimeo) never require a key.
- Confirm the entitlement is present in Admin → License (or
App reads as "unlicensed" after moving domains
- Cause: the license is bound to your domain. After moving, the previously activated record won't match the new host.
- Fix: activate the new domain (Install Wizard or Admin → License). If you're retiring the old domain, Deactivate it first to release the seat.
Storage
Uploads fail with SignatureDoesNotMatch
- Cause: the stored storage secret key is wrong (or the token was rotated). This is configuration, not code. Uploads go server-side to Cloudflare R2 (or any S3-compatible storage) via the AWS S3 SDK.
- Fix: re-enter your credentials in Admin → Settings → Storage — endpoint/account, access key, secret, and bucket. The upload route surfaces the underlying storage error (not a generic 500), so the cause is diagnosable in the response/logs.
Images upload but don't display
- Cause: the stored public base URL is wrong, not publicly reachable, or the raw object key was saved instead of the public URL.
- Fix:
- Confirm the bucket's public URL / custom domain in Admin → Settings → Storage is correct and publicly reachable.
- Confirm the bucket exists and the key has read/write permission on it.
- Ensure the stored value is the public URL, not the raw object key.
Emails not arriving (verification, reset, notifications)
- Cause: SMTP isn't configured or activated. Tours sends mail with
nodemailerover an SMTP integration configured in the database, not an env var. - Fix:
- Configure and activate SMTP in Admin → Settings → Email (SMTP is the free email provider and needs no license key).
- Verify the host, port, username, password, and from-address.
- To avoid spam folders, set SPF/DKIM/DMARC records for your sending domain and use a verified from-address.
Dev Server
A route returns 404 even though it exists and typechecks
- Cause: Turbopack de-registers neighboring routes when a route folder is added or moved in dev — a stale route table, not a code bug.
- Fix:
touchthe affectedpage.tsx/route.ts, or restartnpm run devfor a clean route table. Note that the first request to a freshly added/edited route can take several seconds (on-demand compilation) — that's not a hang.
Build & Env
Build fails on deploy
- Cause: an unsupported Node version or a missing environment variable.
- Fix:
- Node version: Tours requires Node 20+. Set the host's Node version accordingly.
- Missing env var: confirm
DATABASE_URLis present at build/runtime; on Vercel also setJWT_SECRETandNEXT_PUBLIC_SITE_URL. - Read the platform build log — a missing variable or Node version mismatch is named directly there.
Triage Order
A quick order that resolves most problems:
- Read the host/platform logs — the error usually names the fix.
- Confirm env values:
DATABASE_URL,JWT_SECRET, and (on Vercel)NEXT_PUBLIC_SITE_URL. - Confirm in-app integration config: storage and SMTP credentials in the admin panel.
- Verify connectivity: database reachable, storage bucket reachable and public.
- Redeploy / restart, then hard-refresh the browser.
If a problem persists after triage, open a ticket at creative-cape.com or email support@creative-cape.com with your purchase code, version, environment, and reproduction steps. See the Support Policy for what's covered.
© CreativeCape Solutions · creative-cape.com · support@creative-cape.com