Troubleshooting¶
Port 8080 is already in use¶
Symptom: make up fails with address already in use or port is already allocated.
Fix: Stop whatever is using port 8080, or change the port in .env:
Then run make up again.
Import exits immediately or fails with a database error¶
Symptom: The import finishes in seconds (normally takes minutes), or you see a connection refused or role does not exist error.
Fix: The database must be running before you import. Start the stack first and confirm all containers are healthy:
docker compose ps # all containers should show "running" or "healthy"
# then run the importer — replace <mode> with your DEPLOY_MODE (data-node or data-node-ui)
docker compose --profile <mode> run --rm importer
If you are using the local development setup, make import is equivalent. If the database shows as unhealthy, try stopping and restarting the stack.
Map loads but shows no playgrounds¶
Symptom: Map tiles appear (streets and buildings visible) but no playground polygons are drawn, or the detail panel is empty.
Possible causes:
- Import not run — Run the importer after starting the stack (
docker compose --profile <mode> run --rm importer, ormake importfor local dev). Playground data is not loaded automatically. - Wrong relation ID — Check
OSM_RELATION_IDin.env. An incorrect ID filters out all playgrounds. Verify at nominatim.openstreetmap.org. - Docker stack not running — The app requires a live PostgREST backend. Confirm the stack is running and healthy before starting
make dev. - Browser cache — Try a hard reload:
Ctrl+Shift+R(Windows/Linux) orCmd+Shift+R(Mac).
Geolocation button does nothing on mobile¶
Symptom: Tapping the location button on a phone browser has no effect — no movement, no error.
Cause: Browsers block the geolocation API on plain HTTP connections (including local IPs like http://192.168.1.42:8080). This is a browser security policy and cannot be overridden in the app.
Fix options:
- Test geolocation on the production HTTPS URL.
- On Android with Chrome: go to
chrome://flags, search for "Insecure origins treated as secure", add your local URL, and relaunch Chrome. - DuckDuckGo and Brave do not offer this workaround — use Chrome for local geolocation testing.
Dev server starts but changes don't appear¶
Symptom: You edited a JS or CSS file, but the browser still shows the old version.
Fix: Vite hot-reload should pick up changes automatically. If it doesn't:
- Check the terminal running
make dev— a build error will prevent the browser from updating. - Try a hard reload:
Ctrl+Shift+R/Cmd+Shift+R. - If you changed
index.htmlor a file inpublic/, stop and restartmake dev.
Note
When testing via make docker-build (the Docker stack), you must run make docker-build again after every change — there is no hot-reload in that mode.
make lan-url prints "Could not detect LAN IP"¶
Fix: Run this command directly and use the output as your LAN IP:
Then open http://<that-ip>:8080 on your phone.
PostgREST returns 404 or connection refused on /api/¶
Symptom: The app loads but every API call fails with "Failed to fetch" or the network tab shows 502/404 on /api/rpc/*.
Possible causes:
- PostgREST container not running — Check
docker compose ps. Thepostgrestservice should be running and healthy. - Database not ready — PostgREST starts before PostgreSQL finishes initialising on first launch. It retries automatically, but a
docker compose restart postgrestusually resolves it. - Schema cache stale — After running
make db-apply, PostgREST needs a schema reload. The apply script sendsNOTIFY pgrst, 'reload schema'automatically, but if that notification was missed, restart PostgREST:docker compose restart postgrest. web_anonrole missing —db/init.sqlcreates this role on first init. If you deleted and recreated thepgdatavolume without re-running init.sql (e.g. by runningdocker volume rmbut not recreating viadocker compose up), the role is missing. Rundocker compose up -dto let init.sql re-run, or run it manually.
Import fails partway through with a PBF error¶
Symptom: The importer exits with osmium or osm2pgsql reporting a corrupt or truncated file.
Fix: The cached PBF may be corrupt (interrupted download). Delete the cached files and re-run:
docker compose run --rm importer sh -c "rm -f /data/*.pbf"
docker compose --profile data-node-ui run --rm importer
The importer validates the source PBF with osmium fileinfo before using it and will re-download a corrupt file automatically. If the re-download fails, check PBF_URL in .env — make sure the URL is reachable and returns a valid PBF.
Hub shows all backends as red / unreachable¶
Symptom: The instance drawer shows every data-node with a red indicator.
Possible causes:
- CORS not configured — The Hub's browser must be able to reach each data-node's
/api/cross-origin over HTTPS. Verify with: - registry.json not updated — The Hub still has the bundled dev
registry.jsonpointing at/apiand/api2. See Federated Deployment for how to replace it. - Data-node not reachable from browser — The Hub serves the app; the Hub's browser must reach each data-node, not the Hub host. Test from a browser (not the server) by opening each data-node's
https://…/api/rpc/get_metaURL directly. - Hub cron not running — Check
federation-status.json: ifgenerated_atis older than 5 minutes, the cron job inside the hub container has stopped. Restart the hub container:docker compose --profile ui restart app.
make db-apply fails with "permission denied"¶
Symptom: psql reports permission denied when running api.sql.
Cause: The SQL runs as the database user configured in .env. This user needs SUPERUSER or at minimum pg_signal_backend (to terminate PostgREST connections) and CREATE on the public schema. The default compose.yml user (osm) is a superuser — if you changed POSTGRES_USER, verify the role has these privileges.
Fix:
Database volume is very large after repeated imports¶
Symptom: The pgdata Docker volume grows beyond expectations over time.
Cause: api.sql uses DROP MATERIALIZED VIEW … CASCADE + CREATE MATERIALIZED VIEW on every apply. PostgreSQL does not reclaim the space immediately — it marks pages as dead and waits for autovacuum. After many re-imports, dead tuple bloat can be significant.
Fix: Run VACUUM FULL (briefly locks the table):
Or simply recreate the data volume after a re-import — the volume will start clean.
Hub drawer shows "updating" badge that never clears¶
Symptom: One or more backends in the Hub instance drawer permanently show an "updating" badge, even though no import is running.
Cause: The importing flag in api.import_status was left true by an importer that was killed with SIGKILL (bypasses the EXIT trap) or crashed before the trap could fire.
Self-healing: The importer clears the flag automatically at startup. Restarting the container is usually enough:
docker compose restart importer
# or, in daemon mode, the container is already running — it will clear the flag
# on its next scheduled run
Manual fix (if you need it cleared immediately without waiting for a restart):
# From the data-node host
docker compose exec db psql -U osm -d osm \
-c "UPDATE api.import_status SET importing = false WHERE id = 1;"
The Hub will pick up the corrected value on its next poll cycle (within 60 seconds).
Legal pages missing or showing wrong contact details¶
Symptom: /impressum or /datenschutz returns 404, or the pages show stale contact information after updating IMPRESSUM_* vars.
Cause: The HTML files are generated by docker-entrypoint.sh at container startup. A rebuild is required to pick up changed env vars.
Fix:
If get_meta() still returns the old impressum_url / privacy_url after the rebuild, also re-apply the DB schema (legal URLs are baked in at import time via envsubst):
Symptom: /impressum returns 404 despite IMPRESSUM_NAME being set.
Cause: IMPRESSUM_ADDRESS is also required. The entrypoint skips generation when either of the two required vars is empty.
Fix: Set both IMPRESSUM_NAME and IMPRESSUM_ADDRESS in .env, then make docker-build.