The site will not start, or ignores my settings
This page covers the site failing to start and settings that seem to be ignored. It is for whoever runs the server. Run the configuration check first (Troubleshooting): it finds most of these.
My .env file is ignored
On plain Node, nothing reads a .env file. Node does not load it by itself, and neither the launcher nor the server does. The file only works where something else loads it:
| How you run it | How the file reaches the server |
|---|---|
| Docker Compose | Both compose files have env_file: .env. Compose reads it. |
node directly | node --env-file=.env server/launcher.js |
| systemd | EnvironmentFile=/srv/choirmaster/choirmaster.env in the unit |
| A shell | set -a; . ./.env; set +a; npm start |
NODE_OPTIONS=--env-file=... does not work: Node refuses it. Quotes around values are fine with --env-file. If you use a systemd EnvironmentFile, do not put export in front of the names. See Give the server its settings.
Check what the server really sees with the configuration check, started the same way:
node --env-file=.env scripts/check-config.js
If a value is "(not set)" there, it did not arrive. Changing a setting needs a restart; the server reads its settings once, at start-up.
dist/ not found: serving the API only
The full line is [server] dist/ not found: serving the API only. Run npm run build to serve the site too. The server found no built site, only the API. It looks for dist/index.html inside the folder the code was installed in, wherever you start it from.
- A downloaded release always contains
dist/. If it is missing, the archive was not unpacked completely or the folder is not the one you think. Unpack it again into a fresh folder: see Update by hand. - A copy of the source has no
dist/untilnpm run buildhas been run.
failed to start:
A line beginning [server] failed to start: means the site stopped. The reason follows, and for a missing or wrong setting it names the setting. The process exits and your supervisor restarts it, so the line repeats. Common causes:
| The line says | Fix |
|---|---|
Unknown DB_PROVIDER "x". Use sqlite, postgres or mysql (d1 is for Cloudflare). | Correct the spelling. |
Unknown STORAGE_PROVIDER "x". Use local or s3 (r2 is for Cloudflare). | Correct it. |
Unknown SESSION_STORE "x". Use database, redis or memory (kv is for Cloudflare). | Correct it. |
Unknown EMAIL_PROVIDER "x". Use none, log, ses, smtp, resend, sendgrid, mailgun or postmark. | Correct it. |
EMAIL_PROVIDER=resend needs RESEND_API_KEY (or the same for ses, smtp, sendgrid, mailgun, postmark) | Set the keys the provider needs. See Email providers. |
Unknown SECRETS_PROVIDER "x". Use env, vault, aws-secrets-manager, doppler or infisical. | Correct it. |
VAULT_ADDR, VAULT_TOKEN and VAULT_SECRET_PATH are required (or the equivalent for another secrets manager) | Give the secrets manager the variables it names. |
An ECONNREFUSED or authentication error from the database | The database is not reachable at DATABASE_URL, or the password is wrong. For PostgreSQL and MySQL, DATABASE_URL is required: the [config] line DATABASE_URL is needed for DB_PROVIDER=postgres appears just before. |
EADDRINUSE | Another program is using PORT. |
EACCES or SQLITE_CANTOPEN | The service user cannot write to the database folder (DATA_DIR). |
Other [config] lines are warnings: the site starts. For example STORAGE_PROVIDER=s3 needs S3_ACCESS_KEY_ID, ... is printed as a warning and the failure comes later, when a file is uploaded. Fix every warning.
A secrets manager that cannot be reached
This stops the site on purpose. With SECRETS_PROVIDER set to vault, aws-secrets-manager, doppler or infisical, the server fetches its secrets before anything else, and if it cannot, it refuses to start, because a site without its admin login and its email keys would be worse than no site. Check the manager's address and token, that the server can reach it, and the secret path. See Use a secrets manager. Values already in the environment are never overwritten, which is a way to get going while you fix the manager.
[site.config.json] warnings
Lines like [site.config.json] identity: ... mean a value in your site.config.json (the defaults file) did not pass the settings schema. The site starts, and the value that failed is ignored. Fix the file against the original in the download: see Ship your own defaults. Settings already saved in the admin panel are in the database and do not come from this file.
My data is somewhere unexpected
DATA_DIR, SQLITE_PATH and STORAGE_LOCAL_DIR default to ./data, ./data/choir.sqlite and ./data/storage. Those are relative to the folder the server was started from, not to the folder the code is in. Start it from a different folder (a new version folder, a service whose WorkingDirectory changed) and it creates a new empty database there. Your old data is untouched where it was.
Find out where the server is using, then use full paths:
node --env-file=choirmaster.env scripts/check-config.js | grep -E 'sqlitePath|localDir'
DATA_DIR=/srv/choirmaster/data
SQLITE_PATH=/srv/choirmaster/data/choir.sqlite
STORAGE_LOCAL_DIR=/srv/choirmaster/data/storage
A new feature is missing after a Cloudflare update
On Node and Docker the schema is applied each time the server starts. A Cloudflare Worker cannot do that, so after deploying a new version you must add anything new to the D1 database yourself, or a new feature will fail for lack of its table:
npx wrangler d1 execute choir-db --remote --file=./server/db/schema/sqlite.sql
It only creates what is missing, so it is safe to run again. Use your own database name from wrangler.toml. See Update by hand.
A shared link shows "Choir" or the wrong details
From version 1.6.12 the page your site sends carries your choir's name, description, icon and link-preview tags. See what it really sends before anything else:
curl -s https://choir.example.org/ | grep -iE '<title>|name="description"|rel="canonical"|property="og:'
| What you find | Why | What to do |
|---|---|---|
<title>Choir</title> on a Cloudflare Worker | Your wrangler.toml has the [assets] section from before 1.6.12, or only binding = "ASSETS" was added to it. | Put in both lines and deploy: Changes a release needs in wrangler.toml. |
<title>Choir</title> now and then, on any platform | The settings could not be read, or took more than a second and a half, so the page went out as built. The log has The page was served without the site's own title: and the reason. | Look at the reason: it is the database being slow or unreachable. |
<title>Choir</title> always, on Node or Docker | The site is older than 1.6.12, or something in front of it (a CDN, a proxy rule) is serving its own copy of index.html. | Check /api/health for the version. Do not let a proxy cache or serve the pages itself. |
| Your name, but no description | The Description for search engines box is empty, or still holds the sample choir's wording, which is never sent under another choir's name. | Write your own in Site Settings → Choir. |
No og:image line | There is no Background photo in Site Settings → Home: Hero, or it is an SVG, or it was uploaded to the site and SITE_URL is not set. | Set a photo, and SITE_URL. |
No canonical or og:url line | SITE_URL is not set, or is not an http:// or https:// address. On the admin panel, the member portal and personal pages there never is one. | Set SITE_URL. |
The wrong address in canonical and og:url | SITE_URL is wrong. It is never taken from the request. | Correct SITE_URL and restart or deploy. |
| The lines are right, but Facebook, WhatsApp or Slack still show the old preview | The app kept its own copy. | Wait, or use the app's tool for fetching a page afresh. See Check how it looks. |
On Cloudflare, every page answers "Not Found"
Every page of the site shows {"success":false,"error":"Not Found"}, while addresses under /api/ still answer. The [assets] section of wrangler.toml has the new run_worker_first = ["/*", "!/assets/*", "!/images/*", "!/favicon.svg"] but no binding = "ASSETS": pages are sent to the Worker, which has nothing to answer them with. Add the binding line and run npx wrangler deploy. See Your choir's name in the page.
On Cloudflare, pages appear but nothing loads
The frame of the site appears, titled "Choir", with none of your content, and the admin login fails. The Worker could not start (a binding is missing or misnamed, or EMAIL_PROVIDER names a service whose secrets are not set). From 1.6.12, with the ASSETS binding in place, pages are still served as they were built when that happens, so the site is not blank, but the API is down. Run npx wrangler tail, load a page, and read the line starting The site could not be started, so pages are served as built and the API is down:. See Cloudflare: limits and logs.
The browser shows the old version
The site tells browsers to ask for the page afresh each time (Cache-Control: no-cache on the page) and to keep the files in /assets/ forever, because their names change with their contents. A browser shows an old version only when something in the middle keeps the page itself: a reverse proxy, a CDN, or a "cache everything" rule. After a version change the site also reloads a stale page once by itself.
- Do not set your proxy or CDN to cache the HTML pages,
/api/or/files/. Cache only/assets/if you like. - If a CDN has cached the page, purge it.
- To test, request the page with
curl -sI https://choir.example.org/and look at thecache-controlheader. It should beno-cache.