Troubleshooting
A template isn't eligible, or a clone never reaches Ready
Symptom: the VM doesn't show up in the PVE template VM picker on
Templates → Register Existing, or a pool's clones stay stuck in
customizing and their guest facts show Agent not installed or
Agent unknown.
Cause: the QEMU guest agent isn't installed and running inside the guest, or the QEMU Guest Agent option isn't enabled on the VM itself in Proxmox VE — both are required, and enabling one without the other isn't enough.
Fix:
- Install the guest agent inside the guest (
qemu-guest-agenton Linux; thevirtio-winISO'sguest-agentinstaller on Windows) and confirm the service is running. - Enable QEMU Guest Agent on the VM's Options tab in the Proxmox VE UI.
- While the VM is still running as a normal VM (before converting it to a template), open it in the Proxmox VE UI and check the Summary tab — an IP address appearing there confirms the agent is responding.
See Preparing VM templates for the full walkthrough.
A pool is stuck provisioning
Symptom: a pool never reaches its Min Size or warm target; its VMs
stay in planned or cloning.
Cause: most often one of: the Proxmox API token configured for the cluster lacks privileges to clone or create VMs, the pool's Storage target is out of space, or a specific clone job failed outright.
Fix:
- Open the Jobs page and filter to Failed — a stuck pool almost always has a Clone VM job sitting there with an error.
- Read the job's error for a permissions or storage message from Proxmox VE.
- In Settings → Proxmox Connection, confirm the cluster's API Token has clone/create privileges and select Test Connection; separately confirm the pool's configured Storage target has free capacity.
- Once the underlying cause is fixed, select Requeue on the failed job (only jobs in Failed status can be requeued), or act on the VM directly with Recreate or Delete — see Desktop pools → Failure handling.
Browser desktop connections fail
Symptom: selecting Connect in browser shows a status such as "The desktop is currently unavailable." or "The connection was closed unexpectedly. Please reconnect."
Cause: the gateway is unreachable, an intermediate proxy is blocking the WebSocket upgrade, guacd itself is down, or RDP is blocked in the guest's own firewall.
Fix:
- Confirm the gateway process/container is running and reachable at the
public
wss://origin your reverse proxy exposes (GATEWAY_PUBLIC_WS_URL). - Confirm your reverse proxy passes WebSocket upgrades through on that path — a proxy that only forwards plain HTTP silently breaks the tunnel.
- Confirm guacd is running and reachable from the gateway
(
GUACD_ADDRESS). - Confirm the guest's own firewall allows inbound RDP (port 3389) from guacd's address. See Requirements → Network paths for the full path — browser to gateway over WSS, gateway to guacd on the Guacamole protocol (port 4822), guacd to the desktop VM over RDP (port 3389).
OIDC login fails
Symptom: the user is sent to your identity provider but comes back to an error, or signs in successfully but lands with no permissions and no group membership.
Cause: usually one of: a redirect URI isn't registered on the identity provider's application, the token is rejected because of clock skew between the host issuing it and the host validating it (expiry validation has no tolerance for large drift), or the user's token carries a group claim value with no matching OIDC group binding.
Fix:
- Confirm all three redirect URIs are registered on your identity provider's application. See Identity providers → Generic OIDC setup.
- Confirm the clocks on the host running the API and on your identity provider are in sync (NTP) — a token that appears not-yet-valid or already expired because of drift fails verification the same way a genuinely expired token would.
- If sign-in itself succeeds but the user has no access, check Users & Access → OIDC bindings for a binding whose claim value matches what your identity provider actually sends — a claim by itself grants nothing until it's mapped to a local group. See Access management → OIDC group bindings.
/readyz starts failing after an upgrade
Symptom: the API's or worker's /readyz returns 503 {"status":"not_ready","dependency":"migrations"} right after you roll out a new version.
Cause: migrations for the new release haven't been applied yet — they are never applied automatically.
Fix: run the migration step for your install channel, then re-check
/readyz:
- Docker Compose:
docker compose --profile migrate run --rm migrate - VM/systemd: re-run the migrate binary — see Install on a VM (systemd) → Apply database migrations
- Kubernetes/Helm: migrations run automatically as a pre-install/
pre-upgrade hook Job on
helm upgrade— check the hook Job's logs if it fails, see Install on Kubernetes (Helm) → Install
See Observability → Readiness
semantics for the
exact response shape and what each dependency value means.
Where logs live
| Install channel | Command |
|---|---|
| Docker Compose | docker compose logs -f <service> — service names: api, worker, gateway, web, guacd, postgres, redis |
| VM (systemd) | journalctl -u <unit> -f — units: planeon-api, planeon-worker, planeon-gateway, planeon-web, planeon-guacd |
| Kubernetes (Helm) | kubectl get pods -l app.kubernetes.io/instance=planeon to find the pod, then kubectl logs <pod-name> -f — exact labels and pod names are set by the chart, see Install on Kubernetes (Helm) |