# Troubleshooting

> Fix common problems of a self-hosted Nodaro, starting at /setup. Symptoms and fixes for startup errors, ports, CORS, migrations, storage, queues and keys.

Source: https://nodaro.ai/docs/self-hosting/troubleshooting

This page lists the most common problems of a self-hosted Nodaro, each with its **symptom** and its **fix**. Start with the `/setup` page, which shows most of them at a glance.

## Start at /setup

Self-hosted installs serve a live health screen at `http://<your-host>/setup`. It needs no sign-in and shows only whether each part is present and working, never a secret.

- **Cards** for the database, Redis, storage, the encryption key and the provider keys, green or red. The database card has its own **migrations missing** state.
- **A hint** on every failing card, naming the variables to check.
- **Live updates**: the page checks again every 5 seconds.

When the page says **API unreachable**, the web server is up but the API is not answering. Read the container logs with `docker compose -f docker-compose.community.yml logs -f`, and check that nothing blocks port `3000`.

## The install does not start

**`Missing or invalid env vars` on startup.**
The message lists the variables that failed validation. The usual causes are an empty `SUPABASE_SERVICE_ROLE_KEY` and an `INTERNAL_ORCHESTRATOR_SECRET` shorter than 32 characters.

**`port is already allocated` on `docker compose up`.**
The stack publishes only two host ports: `3000` for the app and `9001` for the MinIO console, on loopback. Redis and the database never use a host port. Change the host side of the conflicting mapping in `docker-compose.community.yml`, for example `"3001:3000"`. For the app port, also set `PUBLIC_URL` to match.

**The migrations failed on boot.**
The app's log names the exact file. The API refuses to start against a half-migrated database. Fix the cause and run `docker compose -f docker-compose.community.yml up` again: files already applied are skipped.

**`password authentication failed for user "supabase_auth_admin"` in the sign-in logs.**
The `db-data` volume is older than the database's role setup, or you changed `POSTGRES_PASSWORD` after the first start. The role passwords follow `POSTGRES_PASSWORD` only on the first start. Either delete the volume with `docker compose -f docker-compose.community.yml down -v`, which **deletes your data**, or change the role passwords by hand as `supabase_admin`.

**The Docker build fails to download or verify the ffmpeg archive.**
This only affects you when you build the image yourself. The Dockerfile pins an exact static ffmpeg build per architecture, with `ARG FFMPEG_TARBALL_URL_*` and `ARG FFMPEG_TARBALL_SHA256_*`, because rendered audio and video change between ffmpeg versions. A failed download or a checksum mismatch stops the build instead of silently changing your output. Choose a newer dated release of the same builds (`BtbN/FFmpeg-Builds` on GitHub), and update **both** the URL and the SHA-256 for **both** architectures. Treat it as a real ffmpeg upgrade and check your rendered output afterwards.

## The browser shows errors

**The editor renders, but stays blank or shows "Loading…" forever.**
Open the browser console.

- **CORS errors:** see the next item.
- **Sign-in errors:** open `/config.js` on your install. It must name a Supabase URL that your browser can reach, `PUBLIC_URL/supabase` on the bundled stack, and the anon key. The container writes it at boot from `PUBLIC_URL`, `FRONTEND_SUPABASE_URL` and `SUPABASE_ANON_KEY`: fix those and restart.

**CORS errors in the browser.**
`http://localhost:3000` and `PUBLIC_URL` are always allowed, so you opened the app on another origin, such as a LAN address or another port. Set `PUBLIC_URL` to that origin, or list extra origins, comma-separated, in `CORS_ORIGIN`, for example `CORS_ORIGIN=http://192.168.1.20:3000`. Then run `docker compose -f docker-compose.community.yml up -d`.

**Edit video shows a panel instead of the editor.**
The hosted video editor accepts embedding only from `http://localhost:3000`. On another origin, run your own editor and set `FREECUT_URL`. See [Video and audio editors](https://nodaro.ai/docs/self-hosting/configuration#video-and-audio-editors).

**Edit audio shows a panel instead of the editor.**
There is no hosted audio editor. Run your own AudioMass and set `AUDIOMASS_URL`.

## Database

**A migration fails with "relation … does not exist".**
A migration ran out of order. Apply the files of `supabase/migrations/` in filename order, for example in the Supabase SQL editor. Each one can run again on a database where it is already applied.

**An OAuth callback returns `500`.**
The tables for OAuth apps are missing because a migration was not applied. Apply every migration in filename order. See [Database](https://nodaro.ai/docs/self-hosting/database#apply-the-migrations-to-a-managed-project).

**The API restarts in a loop.**
It cannot reach Postgres. That is expected while the database is down. Once Postgres is back, run `docker compose -f docker-compose.community.yml restart nodaro`.

## Storage

**Uploads fail on the bundled stack.**
Open the MinIO console at `http://localhost:9001`. The default credentials are in the compose file.

**Uploads to Cloudflare R2 answer `401` or `403`.**
Check that the API token has **Object Read & Write** on the bucket. With a custom domain in front of R2, also check the bucket's public access setting: Nodaro gives the browser public media URLs, so reads must work without authentication.

**Every storage request fails with an authorization or endpoint error.**
Set `R2_REGION` to the store's region. AWS, DigitalOcean Spaces and a local Supabase reject the default `auto`, and their error does not mention the region.

**Every upload fails after you set `STORAGE_OBJECT_ACL`.**
The storage keys lack the right to set object ACLs. Leave the variable empty unless your store refuses a bucket policy.

**`[storage] failed to create bucket` in the boot log with R2.**
Harmless. R2 tokens cannot create buckets, and yours already exists.

## Runs and nodes

**Workflows are queued but never start.**
Read the logs with `docker compose -f docker-compose.community.yml logs nodaro`. The orchestrator takes its work from Redis, so nothing runs when Redis cannot be reached. Check `REDIS_URL` and run `docker compose -f docker-compose.community.yml exec redis redis-cli ping`, which should answer `PONG`.

**A node fails with `Missing API key`.**
The node calls a provider that has no key. Add the key on `/setup` or in `.env`. See [Provider keys](https://nodaro.ai/docs/self-hosting/provider-keys).

**Images and video work, but every text feature fails.**
`KIE_API_BASE_URL` names a proxy that forwards only the media paths. See [Send provider traffic through your own proxy](https://nodaro.ai/docs/self-hosting/provider-keys#send-provider-traffic-through-your-own-proxy).

**Pasting a key or connecting to Nodaro Cloud fails with `EncryptionKeyMissingError`.**
The install has no encryption key. With a managed Supabase project, set `NODARO_ENCRYPTION_KEY`, 64 hex characters from `openssl rand -hex 32`.

**Provider keys show `missing` after a restore.**
The database was restored without its matching encryption key. See [Backups and restore](https://nodaro.ai/docs/self-hosting/backups#troubleshooting).

**A node fails with `503 nodaro_connection_required`.**
It is a Nodaro-exclusive node, which needs a Nodaro Cloud connection. See [Connect to Nodaro Cloud](https://nodaro.ai/docs/self-hosting/cloud-connect).

**Cloud runs fail with `Token expired`.**
The connection's 90-day token ran out. Click **Disconnect**, then **Connect**.

**Cloud runs fail with `402 instance_cap_reached`.**
The install reached its monthly spend cap. Raise the cap on app.nodaro.ai, under **Billing › Connected Instances**.

**Healthy runs are marked `Execution orphaned`.**
Two installs share one database with separate Redis instances. Give each install its own `RUNTIME_ENV`. See [Scaling](https://nodaro.ai/docs/self-hosting/scaling#two-installs-one-database).

**3D Render Pro answers `503 SCENE_CAPABILITY_UNAVAILABLE`.**
[3D Render Pro](https://nodaro.ai/docs/nodes/video/pro-3d-render) runs on a hosted build service and is not part of the self-hosted editions. It never falls back silently to another renderer. Use [Generate 3D Scene](https://nodaro.ai/docs/nodes/video/generate-3d-scene) and [Render Video](https://nodaro.ai/docs/nodes/video/render-video), which run on your server.

## Sign-in and MCP

**The SSO routes answer `404 unknown_provider`.**
No provider is configured. Check `EXTERNAL_SSO_PROVIDERS`, and on the compose stack, add it under `environment:` of the `nodaro` service. See [Single sign-on](https://nodaro.ai/docs/self-hosting/sso).

**Every API call answers `403 sso_required`.**
The surface profile allows SSO only, and the account was not created or linked through SSO. See [Sign-in methods](https://nodaro.ai/docs/self-hosting/editions-and-profiles#sign-in-methods).

**An MCP client gets `405 wrong_mcp_host`.**
The client uses the app's main address. Give it the address of your MCP host instead. See [MCP](https://nodaro.ai/docs/self-hosting/mcp).

## Updates

**The version label shows only the built-in version, and the release notes are empty.**
The update check cannot read GitHub. The log line `[update-check] … read failed: HTTP 403 (rate limit: 0 of 60 left…)` means your outbound address has spent GitHub's anonymous quota. Set `NODARO_UPDATE_CHECK_TOKEN`. See [Updating](https://nodaro.ai/docs/self-hosting/updating#which-version-you-run).

## Get help

If you are still stuck, open an issue on [GitHub](https://github.com/nodaroai/app.nodaro.ai/issues) with the Docker logs of the app container.

## Frequently asked questions

### Where do I start when my self-hosted Nodaro misbehaves?

Open /setup on your install. It shows live green or red cards for the database, Redis, storage, the encryption key and the provider keys, with a hint for each failing card, and it needs no sign-in.

### What does port is already allocated mean on docker compose up?

Another program uses port 3000 or 9001 on your machine. Change the host side of that mapping in docker-compose.community.yml, for example to "3001:3000", and set PUBLIC_URL to match.

### Why does the editor stay blank or show Loading forever?

Open the browser console. CORS errors mean the origin you opened is not allowed, so set PUBLIC_URL or CORS_ORIGIN. Sign-in errors mean /config.js names a Supabase URL or anon key the browser cannot use.

### Why do my workflows never start running?

The orchestrator takes its work from Redis. Check the logs with docker compose logs nodaro, check REDIS_URL, and run docker compose exec redis redis-cli ping, which should answer PONG.

### Where can I get help with a self-hosted install?

Open an issue on github.com/nodaroai/app.nodaro.ai with the Docker logs of the app container.
