CHAPTER 17
Troubleshooting
Find the symptom, read the cause, apply the fix. When in doubt, the build log and the app log tell you more than any guess.
Two places to look first
Deploy tab → build log for anything that happens before the app is running, and App tab → follow logs for anything after. The first lines of a build log say which runtime, version and base image the platform chose.
Deploying#
| Symptom |
Cause |
Fix |
cannot autodetect runtime |
none of package.json, requirements.txt/pyproject.toml, composer.json/public/index.php, index.html is at the root |
zip the folder's contents, not the folder; or set runtime: in platform.yaml |
platform.yaml is invalid listing a key |
unknown or mistyped key (the manifest is strict) |
correct or remove the key |
version: must be a quoted string … 3.1 |
YAML read 3.10 as a number |
write version: "3.10" |
cannot pull base image … is that version published? |
that release does not exist |
choose an existing major/minor, or drop version |
Build warns could not refresh …; building from the local copy |
the registry was unreachable; the older local image was used |
harmless once; check the platform's Internet access if it persists |
node runtime: no start command |
no start script, no server.js/index.js |
add a start script or start_cmd |
python runtime: set 'start_cmd'… |
no main.py or app/main.py |
add start_cmd: uvicorn …:app --host 0.0.0.0 --port $PORT |
npm run build fails with command not found (tsc, vite) |
NODE_ENV=production made npm skip devDependencies |
install_cmd: npm ci --include=dev |
php docroot 'public' does not exist |
wrong docroot |
set docroot: to the real web root |
archive too large (> 512 MiB) |
upload or extracted size too big |
remove node_modules, build output and media |
Deployment stuck, then failed … interrupted by management restart |
the platform was restarted mid-build |
deploy again |
The app runs but the site does not#
| Symptom |
Cause |
Fix |
| The site returns an error right after a running deploy |
the app does not listen on 0.0.0.0:$PORT (for example it binds 127.0.0.1 or a fixed port) |
read PORT from the environment and bind all interfaces |
| App tab shows stopped |
stopped by you, or the start command exits at once |
press start; if it exits again read the log |
| App tab shows missing |
the container does not exist (a failed recreate, or never deployed) |
deploy again, or recreate |
| A variable change has no effect |
variables apply on recreate or deploy |
press recreate app now |
DB_MAIN_HOST is empty or missing |
the database did not exist when the app was deployed |
create the database, then recreate (and check the name in databases:) |
| Files written by the app vanish |
they were written outside a volume |
declare a volumes: path, or use S3 or the database |
Build works but process.env.X is empty at build time |
variables are runtime-only |
put build-time values in platform.yaml build_cmd/install_cmd, or read at start |
Domains and certificates#
| Symptom |
Cause |
Fix |
pre-check dns_failed |
no A record, wrong address, or DNS has not propagated |
fix the record; dig +short <name>; press retry pre-check |
pre-check routing_failed |
DNS resolves but the request never reaches the platform |
ingress must forward 80 and 443 to 10.10.10.10; test curl -i http://<name>/.well-known/platform/precheck |
certificate stays pending or error in prod |
port 80 blocked, CA rate limit, bad contact email |
open port 80; use Let's Encrypt staging to rehearse; set a real email (not admin@platform.example) |
| Browser warns not secure |
the platform is in dev TLS mode |
import the local CA, or have the admin switch to prod |
Adding a custom domain answers 409 |
a hostname belongs to exactly one project, platform-wide, however it is spelled |
remove it from the project that holds it, or choose another name |
Databases#
| Symptom |
Cause |
Fix |
| Password lost |
it is shown once and stored encrypted |
the app still receives it as DB_*; for new credentials create a new database and move the data |
| SQL result cut off |
1 000 rows / 1 MiB cap |
add LIMIT, select fewer columns, or dump |
| Query stopped after 30 s |
per-statement timeout |
optimise, or run it from your app |
| Only one statement runs |
the console executes a single statement |
send statements one at a time |
| A Postgres 16 database will not become 17 |
a 16 data directory cannot start under 17 |
create a new database and dump/restore into it |
Uploads, tokens and MCP#
| Symptom |
Cause |
Fix |
HTTP 413 Request body too large from MCP |
upload_archive carries the file as base64; the limit is 4 MiB (≈ 3 MiB archive) |
use create_upload_url and curl -T the file |
Upload link answers 404 |
the link is unknown, expired (15 min) or already used |
request a new one with create_upload_url |
Upload link answers 413 archive exceeds 512 MiB |
over the cap |
shrink the archive |
/mcp redirects to http:// or loses the token |
trailing slash missing |
use /mcp/ |
authentication required / invalid, revoked or disabled token |
no, wrong or revoked token |
create a new token on the tokens page |
tool requires the admin role |
an admin-only tool called by a regular user |
use an admin token, or ask an admin |
project … belongs to another user |
wrong project id or slug |
list_projects |
| The Ukrainian console shows an English error such as «Помилка: Incorrect email or password» |
server messages are not translated — the console translates its own wording and passes the server's text through |
expected; the English detail is the real message |
| The console logs you out after a while |
a JWT lasts 8 hours |
sign in again; use an API token for long jobs |
For administrators#
| Symptom |
Cause |
Fix |
platform health shows degraded |
a component is down |
open the failing row; make check and make logs on the host |
Deleting a user answers 409 user has N project(s) |
users with projects cannot be deleted |
delete or transfer the projects first |
| Brief connection drops after saving ACME settings |
applying recreates Traefik |
expected; wait a few seconds |
| After a CA change every certificate is re-issued |
each CA keeps its own certificate store |
expected; plan it outside peak time |
make up fails with an egress error |
the host does not forward/masquerade hosting |
fix the host's forwarding, or set SKIP_EGRESS_CHECK=1 knowingly |
Large PUT uploads fail through the ingress |
body size limit, buffering or timeouts |
see Operations |
Still stuck? The FAQ answers the questions people ask most, and the audit trail shows exactly what was done and by whom.