Administrator troubleshooting¶
Operational failure patterns in saas.provisioner, for diagnosing a stuck
or failed instance from the platform side (see
Provisioning issues for the
customer-facing version of this).
Provisioning failed, instance stuck in “error”¶
Every provisioning failure is caught, logged with _logger.exception, and
triggers an automatic rollback
(_rollback_failed_provision / _rollback_failed_provision_docker) before
the instance is written to state: error. Rollback deletes the
Deployment/Service/Ingress (Kubernetes) or removes the container (Docker) —
but never touches the tenant’s database or filestore/addons volumes, so
retrying provisioning after fixing the underlying issue doesn’t lose data.
Check instance.error_message first — it’s the raw exception string, and
instance.log_activity() records a matching “ERP Provisioning Failed”
activity entry.
Exit code 137 during initialization¶
See Resource limits § Diagnosing resource exhaustion
— this is almost always an OOM kill. On Docker, the rollback path logs the
container’s OOMKilled/ExitCode state before removing it, specifically
so this is diagnosable after the fact.
LockNotAvailable: could not obtain lock on row in relation "ir_cron"¶
This means --max-cron-threads=0 (disable_cron=True) wasn’t in effect
during initial boot — the persistent server’s own cron thread and the
separate odoo -i base exec were both touching ir_cron rows
concurrently. On Kubernetes this is controlled by
create_kubernetes_deployment(..., disable_cron=True) during the first
boot, then redeployed with cron re-enabled after initialize_odoo()
succeeds. On Docker, initialize_odoo_docker() avoids this entirely by
running -i base in a one-off container before the persistent container
exists at all — if you see this error on the Docker backend, something is
creating the persistent container too early.
Kubernetes deployment stuck “still terminating after 60s”¶
Deployment deletion (before recreating) waits up to 60 seconds for the old
Deployment to actually disappear before giving up and attempting to create
the replacement anyway, retrying the create itself up to 5 times on 409
conflicts. If you see this warning repeatedly for the same tenant, check
for a stuck finalizer on the Deployment rather than assuming the
provisioner is at fault.
Metrics missing or all zero¶
Kubernetes — requires
metrics-serverinstalled in the cluster;_collect_metrics_kuberneteslogs and continues (doesn’t fail the whole run) if themetrics.k8s.ioAPI call fails for a given pod.Docker — reads
container.stats(); CPU percent is computed from a single instantaneous delta rather than a rolling average, so a very idle or very bursty container can look artificially low/high on any single poll.Both backends still record database size (via
pg_database_size) and filestore size (viadu, run inside a throwaway/exec context — never read directly off the host filesystem from the platform container) even if live CPU/memory metrics fail.
Cloudflare DNS record exists but doesn’t verify¶
Addon deployment succeeded but the module doesn’t appear¶
Deploying an addon via Git (deploy_addon_to_instance) only gets the code
into /mnt/extra-addons/<addon> and restarts the tenant — it deliberately
does not call install_custom_module[_docker](). The customer still
has to trigger “Update Apps List” and then explicitly install the module
from Apps. See
Architecture § Custom addons — Git ADD is
not Odoo INSTALL, by design.