Skip to the article
Aniq-UI

KinoraTroubleshooting

Troubleshooting

The errors you can meet while installing Kinora, what causes each one, and how to fix it.

For the Full Stack package

Docker is not running

What you see
failed to connect to the docker API at unix:///…/docker.sock; check if the path is correct and if the daemon is running

Older Docker versions say "Cannot connect to the Docker daemon" instead. Either way, the Docker engine is not started.

  1. Open Docker Desktop

    Start Docker Desktop and wait until it reports that the engine is running. On Linux, start the service: sudo systemctl start docker.

  2. Check that Docker answers

    Terminal
    docker info

    Expected result: It prints a Server section instead of an error.

  3. Run your start command again

    docker compose up --build for the full stack, or your docker build and docker run for a single app.

A port is already in use

What you see
ports are not available: exposing port TCP 0.0.0.0:3030 … bind: address already in use
Error: listen EADDRINUSE: address already in use :::3030

The first line comes from Docker, the second from yarn dev. Another program already listens on 3030 or 8000: often an earlier run of Kinora, or another project's dev server.

  1. Find what holds the port

    On macOS or Linux:

    Terminal
    lsof -i :3030

    On Windows, in PowerShell:

    Terminal
    netstat -ano | findstr :3030
  2. Stop it

    Close that program, or stop the earlier run: Ctrl+C in its terminal, docker compose down in its folder, or docker stop for a container you started with docker run. Then start Kinora again.

  3. Or run Kinora on other ports

    With the full stack in Docker, create a file named .env in the kinora-fitness-full-stack folder, next to docker-compose.yml, with the port you need. DASHBOARD_PORT moves the dashboard and API_PORT the API; the addresses the apps use follow by themselves.

    kinora-fitness-full-stack/.env
    DASHBOARD_PORT=3040

    Then run the same command again. After a failed start it picks up where it stopped:

    Terminalin kinora-fitness-full-stack
    docker compose up --build

    Expected result: The dashboard answers on its new port, here localhost:3040Local.

Without Docker the ports are set in the .env files. To move the API there, change PORT in back-end/.env and both API addresses in dashboard/.env together. To move the dashboard, change PORT in dashboard/.env and CORS_ORIGIN in back-end/.env. With Docker, use API_PORT and DASHBOARD_PORT instead. For a single app started with docker run, change the number on the left of -p.

Configuration

The Docker build fails

The first build downloads the base images and every dependency, then builds the images. It stops with "failed to solve" and the step that failed when something gets in the way.

  • No connection or a timeout: the build needs internet access. Run the command again once you are online; finished steps are cached.
  • No space left on device: free space in Docker Desktop, or check what Docker uses with docker system df.
  • It fails at the same step every time: rebuild without the cache, then start.
Terminalin kinora-fitness-full-stack
docker compose build --no-cache
docker compose up

For a single-app package, add --no-cache to your docker build command.

A first start that seems stuck is usually still seeding the demo data. The dashboard starts only once the API reports itself healthy.

Yarn says its version is 1.22

What you see
This project's package.json defines "packageManager": "yarn@4.8.1…". However the current global version of Yarn is 1.22…

Each app pins Yarn 4 through Corepack. This message means Corepack is not enabled yet, so the old global Yarn answered instead.

Terminal
corepack enable

Then run yarn install again. If your Node.js has no Corepack, install it first with npm install -g corepack.

The API stops before starting

What you see
✖ The API cannot start: JWT_SECRET is not set. Set it in back-end/.env to the output of: …
✖ The API cannot start: JWT_SECRET is still the example value from .env.example, …
✖ The API cannot start: CORS_ORIGIN is not set. List the dashboard origin (comma separated if there are several), …

The API checks its settings before it starts and prints one line per problem. The causes:

  • There is no `.env` file, or `JWT_SECRET` is empty. Create the file in back-end/ with cp .env.example .env.
  • `JWT_SECRET` is still the example value with `NODE_ENV=production`. Anyone could sign a token with the public example, so a production start refuses it. Generate your own secret.
  • `CORS_ORIGIN` is empty with `NODE_ENV=production`. Set it to the dashboard's address, comma separated if there are several.

Generate a secret with:

Terminal
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"

With Docker you do not need one: a container without a JWT_SECRET of its own, or with the example one, generates a secret and keeps it in the data volume.

The health check answers 503

What you see
{"status":"unavailable"}
The database has no tables yet. Run `yarn seed` in back-end/, then restart the API.

/api/health answers 503 until the database answers and holds its tables. The second line is what the API's log says at start-up when the tables are missing.

  • Without Docker, in development: run yarn seed in back-end/ (tables and demo data), or yarn db:sync (tables only), then restart the API.
  • With `NODE_ENV=production`: the API does not create tables by itself. Run yarn db:sync:prod (empty tables) or yarn seed:prod (with the demo data) once, after yarn build.
  • With Docker on SQLite: the container creates the tables by itself on first start. On MySQL it does not: its log says to run node dist/database/sync-schema.js (tables) or node dist/database/seeder.js (tables and demo data) once yourself.
  • "The database has no accounts, so nobody can sign in" means the tables exist but no account was ever added: run yarn seed in back-end/.

MySQL refuses to start or to seed

The API creates its tables in a database that already exists; it does not create the database itself. Create an empty database first, give its name to DB_DATABASE in back-end/.env, then run yarn seed (or yarn db:sync for the tables with no demo data).

  • Check the five DB_* connection values and that DB_TYPE=mysql.
  • With NODE_ENV=production the running API never creates tables, so one of those commands runs before the first start: yarn db:sync:prod or yarn seed:prod after yarn build.

Sign-in fails

  • Check the account. Everyone signs in at the same form on port 3030: the Head Coach is headcoach@example.com with Coach@123, the member member@example.com with Member@123.
  • Check the API's log. "The database has no accounts, so nobody can sign in" means the demo data was never added. Without Docker, run yarn seed in back-end/. With Docker, the volume was created with SEED_DEMO_DATA=false.
  • "The database has no tables yet" means the schema was never created: run yarn seed in back-end/ and restart the API.
  • You changed the Head Coach's password and no longer have it: start over with fresh demo data, below.
  • "That email and password combination didn't work. Please try again." is the one answer for an unknown email and for a wrong password alike, so check both.
  • "Too many attempts. Wait a minute and try again." means one address made more than 10 tries on the sign-in, registration or account-deletion route within a minute. Wait a minute and try again.

Sign-in fails

  • Check the API's log. "The database has no accounts, so nobody can sign in" means the demo data was never added: run yarn seed, or start the Docker container with -e SEED_DEMO_DATA=true on a new volume.
  • "The database has no tables yet" means the schema was never created: run yarn seed and restart the API.
  • Check the account. Everyone signs in at POST /api/auth/login: the Head Coach is headcoach@example.com with Coach@123, the member member@example.com with Member@123. A failed sign-in answers 401 with the same message whether the email or the password is wrong.
  • A `429` answer means one address made more than 10 tries on the sign-in, registration or account-deletion route within a minute. The Retry-After header says how many seconds to wait.

Sign-in fails

On the sample data the password is not checked, but the form still asks for at least 6 characters. An email that belongs to a sample account signs in as that account, and any other email signs in as the Head Coach. Once you connect an API, sign in with an account that exists in it: the demo Head Coach is headcoach@example.com with Coach@123, and the demo member member@example.com with Member@123.

Every visitor gets "Too many attempts" behind a proxy

Sign-in, registration and account deletion allow 10 requests a minute per address and route, then answer 429. The API finds the visitor's address in X-Forwarded-For only when the request comes from a proxy on a private, loopback or platform address, as in Docker, on Railway or behind a reverse proxy on the same machine.

When your proxy reaches the API from a public address, every visitor looks like that one proxy and they share one allowance. Tell the API how many proxies stand in front of it:

back-end/.env
TRUST_PROXY=1

TRUST_PROXY=false never reads the header. Leave it unset when the API is reached directly or through a proxy on a private address. The counts live in the API's memory, so a restart clears them.

A "Sample data" notice appears

What you see
No API is connected (NEXT_PUBLIC_API_BASE_URL is empty), so the dashboard is running on built-in sample data: …

The dashboard was started or built without NEXT_PUBLIC_API_BASE_URL, so it answers every request from sample data in the browser. What you change is then kept in the browser, not in the database.

  1. Give the dashboard the API's address

    Create dashboard/.env from .env.example if it has none. NEXT_PUBLIC_API_BASE_URL must be the API's address including /api, for example http://localhost:8000/api, and NEXT_PUBLIC_WEBSOCKET_BASE_URL the same server without it.

  2. Check that the API answers

    Open localhost:8000/api/healthLocal. It should answer {"status":"ok"}. If the address is set but the API does not answer, the pages cannot load their data: the sample data does not stand in for it.

  3. Restart or rebuild the dashboard

    The address is compiled in. Restart yarn dev after changing it, run yarn build again before yarn start, or with Docker run docker compose up --build again.

A change to the dashboard's .env does nothing

Every NEXT_PUBLIC_* value is compiled into the JavaScript the browser loads when the app is built. Changing the file changes nothing until the app is built again.

How you run itAfter changing a value
yarn devStop it and run yarn dev again.
yarn build and yarn startRun yarn build again, then yarn start.
Docker ComposeRun docker compose up --build. Set API_URL, DASHBOARD_URL or MEDIA_HOSTNAME in the .env next to docker-compose.yml, not in the dashboard's folder.
docker build for the dashboardBuild the image again with the value as a --build-arg.

A feature says it is not set up

Uploads and the AI assistant switch on only when their keys are in back-end/.env. A key still holding its exact .env.example value counts as not set, so a copied .env.example starts cleanly and each of those features reports itself off instead of failing on its first call.

  • Paste your real key over the example value, not next to it.
  • Restart the API after changing back-end/.env. With Docker Compose the API reads that file too, so docker compose up again is enough; a single API container needs --env-file .env on its docker run.

Uploads are refused

What you see
File storage is not configured on this server. Set the R2 variables in .env to enable uploads.

Profile pictures, progress photos and message attachments go to a Cloudflare R2 or other S3-compatible bucket, and an upload answers 400 with this message until the five R2_* variables are set in back-end/.env. The demo data needs no bucket: its pictures are /assets/images/… paths the dashboard serves from its own public/ folder.

Requests are blocked on your own domains

What you see
Access to XMLHttpRequest at 'https://api.your-domain.com/api/…' from origin 'https://app.your-domain.com' has been blocked by CORS policy

The API answers browsers only from the addresses in CORS_ORIGIN, and its live sockets only from FRONTEND_URL when it is set (otherwise from the same list). Both default to the local dashboard on port 3030, so on your own domain they must name it.

back-end/.env
CORS_ORIGIN=https://app.your-domain.com
FRONTEND_URL=https://app.your-domain.com

Write each address exactly as the browser shows it, with https:// and without a trailing slash, then restart the API. With Docker Compose, set DASHBOARD_URL and API_URL in the .env next to docker-compose.yml instead and run docker compose up --build: the compose file builds both values from them.

"Forgot password" sends nothing

The dashboard's forgot-password and reset-password pages are the screens only: no reset is sent, and no password changes through them. They call POST /api/auth/forgot-password and POST /api/auth/reset-password, which the template's API does not have, so against the API the form shows an error. On the sample data the form shows its confirmation, but nothing is sent there either. To give a member a new password, a staff account with members.update sets it on the member's page under Gym. A self-service reset needs both routes and a mail provider of your own.

The API container cannot find its entrypoint

What you see
exec /usr/local/bin/docker-entrypoint.sh: no such file or directory

The script has Windows line endings, which an editor or Git on Windows can add. The shipped back-end/Dockerfile strips them while it builds, so this appears only with an image built from a changed Dockerfile. Keep its sed -i 's/\r$//' line, or save the script with LF line endings, then rebuild without the cache.

Terminalin kinora-fitness-full-stack
docker compose build --no-cache api
docker compose up

The folder looks different

Run the commands inside the folder the ZIP extracts to. If the unzip command is missing, extract it with your file manager instead; some tools add an extra folder named after the ZIP, so move into the inner one.

PackageFolderContains
Full Stackkinora-fitness-full-stackback-end, dashboard, docker-compose.yml
Dashboardkinora-fitness-dashboardDockerfile, package.json, .env.example
Backendkinora-fitness-backendDockerfile, package.json, .env.example

Start over with fresh demo data

This deletes your data

Everything you created locally is removed, and the demo data is seeded again.

With Docker Compose, from the kinora-fitness-full-stack folder:

Terminalin kinora-fitness-full-stack
docker compose down -v
docker compose up

With a single API container, remove the container first (docker ps -a lists it, docker rm -f with its id removes it), then delete the volume and run it again:

Terminalin kinora-fitness-backend
docker volume rm kinora-data
docker run -p 8000:8000 -v kinora-data:/data -e SEED_DEMO_DATA=true kinora-api

Without Docker, stop the API, then in its folder:

Terminal
rm -f database.sqlite* && yarn seed

In PowerShell:

Terminal
Remove-Item database.sqlite*; yarn seed

Running yarn seed again on a database you keep is not a reset: it adds only what is missing and never changes a row you edited. yarn db:reset drops every table, on SQLite and MySQL alike, before yarn seed.

Start over on the sample data

Without an API, your changes are kept in the browser. To bring the sample data back, run this in the browser's console on the dashboard's page:

Browser console
localStorage.removeItem("mock_db_v1"); location.reload();

Stuck on a step?

Find a fix before you start over.

Troubleshooting

Cookie Preferences

We use cookies to enhance your browsing experience, analyze site traffic, and personalize content. By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising.