Skip to content

Troubleshooting

Not logged in. Run pywa cloud login first. — every command except login needs a stored token. Run pywa login.

Could not reach the control plane at <url> — the CLI couldn’t connect at all (wrong --api-url, the control plane isn’t running, or a network/firewall issue) — distinct from an authentication failure, which would connect fine and return a 401/403 instead.

Invalid email or password (signup/login) — exactly that; there’s no separate “account doesn’t exist” vs. “wrong password” message, deliberately, so a failed login attempt can’t be used to enumerate which emails have accounts.

pywa deploy prints the full build log on failure — read it top to bottom, the actual error is almost always in there, not just “build failed.” A few failure modes worth knowing about specifically:

  • Python syntax check failed — every .py file in your project is checked before a Docker build even starts, so a syntax error fails fast with a clear file/line rather than a slower, vaguer Docker build failure. If you’re on macOS and see a syntax error in a file you don’t recognize (e.g. ._main.py), that’s not your code — see below.
  • A file like ._main.py shows up in the error — macOS’s tar command writes an invisible “AppleDouble” metadata file (._<name>) alongside any file with extended attributes when you archive a project by hand. These are automatically ignored during the syntax check, so this shouldn’t happen from a current CLI/dashboard version — if you see it, you’re likely using an old version or building the archive with a different tool; update and retry.
  • Project must include one dependency file: uv.lock, pylock.toml, pyproject.toml, or requirements.txt — exactly that; add one of these declaring pywa[server] (not just pywa — the [server] extra is what pulls in the ASGI server Pywa Cloud’s runtime actually runs). If the file is present but doesn’t declare the right extra, the build itself will still succeed, but the container will fail at startup instead (see “keeps restarting” below) - this check only catches the file being missing entirely.
  • Archive too large — the current limit is 50MB. Make sure .venv/__pycache__/.git aren’t being included (they’re excluded automatically by the CLI’s own archive builder, but a hand-built archive via the dashboard’s file-upload flow won’t get that for free).
  • Build timed out — the default build timeout is 10 minutes. A build that legitimately needs longer than that (a very large dependency set) is unusual - check whether a dependency is hanging on a slow/unreachable index first.

After a successful deploy, the bot keeps restarting

Section titled “After a successful deploy, the bot keeps restarting”

Check pywa cloud status for restart_count and whether it’s flagged as a likely restart loop, then pywa cloud logs for what’s actually crashing. The most common first-deploy cause: pywa’s own server refuses to start without a verify_token -

Error: When listening for incoming updates, a `verify_token` must be provided.

— meaning PYWA_VERIFY_TOKEN (and usually PYWA_TOKEN/PYWA_PHONE_ID) aren’t set yet. Either set them by hand (pywa cloud env set PYWA_VERIFY_TOKEN ...) or, more commonly, connect a real WhatsApp number first (pywa cloud connect) — completing that flow sets all of these automatically. A crash-looping bot with no WhatsApp number connected yet is expected, not broken.

Health check says “unhealthy” — what do the reasons mean?

Section titled “Health check says “unhealthy” — what do the reasons mean?”

pywa cloud health reports one of:

  • webhook_challenge_rejected — this one means healthy. pywa’s webhook handler correctly rejecting an unauthenticated challenge request (HTTP 403) is exactly what a real, running pywa server does — the naming is about what the check itself did, not the outcome. This is also why pywa cloud logs periodically shows a WARNING pywa.server: Failed verification challenge: invalid verify token line even on a perfectly healthy bot — that’s this same health check hitting your bot, not a real failed request from Meta or a customer.
  • not_running — the container isn’t running at all; check status first.
  • no_port_mapping — the container is running but has no recorded port to check yet (typically right after a deploy) — retry in a few seconds.
  • unreachable — the container is running but didn’t respond to the health check at all (still starting up, or genuinely stuck) — check logs.
  • unexpected_response — the container responded, but not with the specific 403 a real pywa webhook handler gives — worth checking logs for what’s actually being served.

Include the full output of pywa cloud status, pywa cloud health, and the last 50-100 lines of pywa cloud logs when asking for help — most of what’s needed to diagnose a stuck deploy is in those three, not in describing the symptom alone.