OBM

Troubleshooting

Symptom, cause, fix — for the failures that actually happen: listing rejected, wrong master password, HTTP 413 on restore, timeouts, TLS trouble, verification failures, size anomalies, stuck jobs, and CE lockouts.

Every entry here is a real failure with the message OBM actually shows you, what causes it, and what to do about it. Messages are deliberately specific — OBM would rather name a cause than hand you "backup failed" — so if you have an error string, search this page for it first.

Entries are tagged CE, Pro or CE + Pro depending on which edition they can happen in.

Backups that fail

"instance refused the backup … this instance has list_db disabled" CE + Pro

Cause. Odoo 17 and later check the requested database against the database listing before dumping it, so an instance with list_db = False cannot be backed up over HTTP at all — the endpoint refuses, and it refuses with the same generic error page Odoo shows for a wrong master password. OBM probes the listing endpoint after any refusal precisely so the job error can name the real cause instead of blaming your password.

Fix. Pick one of three. Re-enable listing and lock the database manager down at the proxy instead — you get backups back without exposing the manager to the internet:

# odoo.conf — the setting that matters
list_db = True

# ... then keep the manager off the internet at the proxy instead:
#   nginx:  location ~ ^/web/database/ { deny all; }
#   caddy:  @dbmgr path /web/database/*   →   respond @dbmgr 403

Or, on the Agency plan, leave the instance hardened and back it up over SSH instead — see SSH backups. Or accept that this server is backed up out of band and don't register it. Note that dbfilter is not the setting involved here; only list_db gates the backup endpoint.

"instance refused the backup … most likely a wrong master password" CE + Pro

Cause. The listing endpoint answered fine, so the refusal isn't about list_db — it's credentials. Odoo replies to a bad master password with HTTP 200 and an HTML error page, which is why OBM inspects the content type instead of trusting the status code. An error page is never stored as a backup.

Fix. Re-enter the instance's master password — it is the admin_passwd value from that server's odoo.conf, not an Odoo user's login. Watch for a trailing space when you copy it. If admin_passwd was written as a hash (Odoo 12+ supports that), you need the original plaintext; you cannot recover it from the hash, so set a new one on the server.

Never guess a master password to "see if it works". If the instance is still on Odoo's default, the first backup request sets the master password to whatever you sent.

"cannot reach instance (ConnectTimeout)" CE + Pro

Cause. A connect-level failure — nothing was received, not even an error page. DNS, a firewall, a wrong port, a stopped Odoo, or simply no route from the machine OBM runs on to that host. The class name in the parentheses tells you which: ConnectTimeout (nothing answered), ConnectError (actively refused or unresolvable).

Fix. Reproduce it from the machine OBM runs on — not from your laptop, which very often has different network access:

# from the machine running OBM, not from your laptop
curl -sS -o /dev/null -w '%{http_code}\n' https://odoo.example.com/web/login
curl -sS -X POST https://odoo.example.com/web/database/list \
     -H 'Content-Type: application/json' \
     -d '{"jsonrpc":"2.0","method":"call","params":{}}'

Check the registered URL is exactly the origin, including scheme and any path prefix. This class of failure is the only one OBM retries automatically, so expect a couple of attempts before the job gives up.

Self-signed or mismatched TLS on the Odoo host CE + Pro

Symptom. "cannot reach instance (ConnectError)" against a server you can reach fine in a browser after clicking through a warning.

Cause. OBM verifies TLS certificates by default. A self-signed certificate, an expired one, a hostname that doesn't match, or a missing intermediate in the chain will all fail verification even though the port is wide open. Browsers hide this behind a click; a backup tool should not.

Fix, in order of preference:

  • Fix the certificate. A free ACME certificate, or your internal CA installed on the machine running OBM, and this goes away permanently.
  • Turn off Verify TLS for that one instance. The instance is then marked TLS unverified in the UI, and you should know exactly what you gave up: the connection is still encrypted, but no longer authenticated. Anything that can get between OBM and that host can present its own certificate and collect the master password you send. Only reasonable on a private network you control.
curl -v https://odoo.example.com/web/login 2>&1 | grep -i 'certificate\|verify\|SSL'
openssl s_client -connect odoo.example.com:443 -servername odoo.example.com </dev/null

Timeouts on very large databases CE + Pro

Symptom. "backup transfer failed mid-stream (ReadTimeout)" — or, on the SSH path, "ssh dump timed out after 3600s" — on your biggest database, usually after about an hour.

Cause. The read timeout covers the whole operation, and Odoo builds the entire archive before it sends the first byte. On a large database with a big filestore, the clock can run out while nothing is flowing at all: the server is still zipping. A reverse proxy in front of Odoo adds its own, usually much shorter, response timeout — Cloudflare's is on the order of a hundred seconds, which no large backup will ever meet.

Fix.

  • Take a db-only dump for that database. Turning off "include filestore" gives you a .dump instead of a .zip: dramatically faster and smaller, because the filestore is the slow half. You then back the filestore up separately (rsync, restic, a volume snapshot) — for many people this is the better architecture anyway.
  • Point OBM at an origin that bypasses the proxy, so only Odoo's own timeout is in play.
  • On CE, raise the timeout in .env and restart. On Pro, ask us — it's a platform setting.
# .env — the read timeout covers the WHOLE transfer, including the time
# Odoo spends building the archive before a single byte moves
READ_TIMEOUT=10800

"disk space low: 812 MiB free, 4096 MiB required — backup not attempted" CE + Pro

Cause. A pre-flight check. Before starting a download OBM requires free scratch space of at least 1 GiB, or 1.5× the size of the previous backup of that database — whichever is larger. Refusing to start beats filling the disk halfway through and taking the rest of the system down with it.

Fix. Free space or grow the volume. On CE, that's the disk holding ./data; tighten retention keep-rules if archives are what filled it. Note the check runs before retention would prune, so it can fire even when a prune is about to happen.

"backup response was only 214 bytes — treated as failure" CE + Pro

Cause. Something replied with a body too small to be a backup. Almost always there is a login wall, WAF interstitial or maintenance page in front of Odoo, and OBM captured that instead of an archive.

Fix. curl the URL from the OBM host and read what actually comes back. If something sits in front of /web/database/*, either exempt the OBM host or register a URL that bypasses it.

"Plan limit reached" / "Storage limit exceeded" Pro

Cause. Plan limits are hard caps rather than metered overage, so OBM declines new work instead of quietly billing you for it. You'll see one of: "Plan limit reached: 15 databases on the growth plan", "Storage limit exceeded — delete backups or upgrade to resume", "Subscription inactive — backups are paused", or "SSH backups require the Agency plan".

Fix. Delete archives you no longer need, tighten retention, or upgrade. Nothing you have already backed up is touched, throttled or deleted by any of these — only new work is blocked. See plans and limits.

Restores that fail

HTTP 413 on restore, behind a proxy CE + Pro

Symptom. On Pro, a restore job fails with "target instance rejected the restore upload as too large (HTTP 413)". On CE, where restores are done by hand through Odoo's own database manager, the proxy returns a bare 413 Request Entity Too Large page and Odoo never sees the upload at all.

Cause. A reverse proxy or CDN in front of the target Odoo caps request-body size, and a multi-gigabyte archive blows through it long before Odoo sees it. Cloudflare's cap on the free plan is 100 MB; nginx's default client_max_body_size is 1 MB.

Fix — any one of:

# nginx, in the Odoo server block
client_max_body_size 0;      # or a generous cap: 8G
proxy_read_timeout   3600s;
proxy_send_timeout   3600s;
  • Raise the cap, as above, and reload the proxy.
  • Restore against a direct origin that bypasses the proxy, or on the Odoo host itself — the exact curl is in Restore a backup.
  • Use the db-only .dump with pg_restore, which never crosses HTTP at all.

Record it so nobody rediscovers it mid-incident Pro

When an instance simply cannot accept restore uploads, turn restore off on that instance and write the reason in the field next to the switch ("Cloudflare 100 MB cap — restore from the origin, see runbook"). The instance is then flagged restore off in the UI, and your reason — not a generic refusal — is what comes back from the API if anyone tries. Restore drills obey the same switch, since a drill is a restore.

"instance reported a restore error — check the master password and that the target database name is valid" Pro

Cause. Odoo answered 200 but the body carries an error marker instead of the manager page. Two usual reasons: the master password of the target instance is wrong (easy to miss when restoring a client's backup into a different instance than the one it came from), or the target database name already exists or isn't a valid PostgreSQL identifier.

Fix. Re-enter the target instance's master password and choose a fresh target name. Restoring as a copy under a new name is always the safer first attempt.

"restore rejected (HTTP 502)" or (HTTP 504) Pro

Cause. Odoo's restore endpoint doesn't answer until the restore has actually finished, so a proxy with a normal gateway timeout will hang up on a long restore even though the restore itself is proceeding fine.

Fix. Before retrying, check on the server whether the database landed — a blind retry can leave you with two half-restored copies. Then restore off-proxy, or raise the proxy's read timeout as in the 413 fix above.

Verification results and warnings

"verification failed: CRC check failed at member: …" CE + Pro

Cause. The archive arrived complete enough to open but one of its members doesn't match its checksum — corruption, either on the source disk or in transit. Related verdicts from the same check: "not a valid zip archive", "CRC/decompression check failed: …", and "zip is missing required members: dump.sql, manifest.json" — that last one means what arrived wasn't an Odoo backup zip at all.

Fix. Retry once; a single corrupt transfer happens. If it repeats, suspect the Odoo host's storage or whatever sits in the network path. What matters meanwhile: a backup that fails verification is rejected, not stored, so your newest good archive is still the newest archive you have — but the database is now going without fresh backups, and that clock is running.

"verification failed: missing PGDMP header — not a pg_dump custom-format archive" CE + Pro

Cause. The same check, for db-only dumps: OBM reads the first bytes and expects PostgreSQL's PGDMP magic. Over HTTP this means an error body slipped through. Over SSH it almost always means the SSH user's shell prints something — a banner, a motd, an echo in a startup file — and that text is now sitting at the front of your dump.

Fix. For the SSH path, make the account silent for non-interactive sessions, then run test-connection again. See SSH backups.

Size-anomaly warning on a backup that succeeded Pro

Cause. Not a failure. The backup verified and was stored; OBM is telling you it changed size by more than the configured threshold (40% by default) against the previous run. The point is to surface the partial dump that technically succeeded.

Fix. Explain it or investigate it. Benign explanations: a module install or data import, an attachment purge, retention running inside Odoo, or a first backup after switching a database between zip and db-only — that one always trips it, because the two formats are nothing like the same size. What deserves a look is an unexplained shrink: run a restore drill and confirm the archive still produces a working database.

Jobs that don't move

A job sits in "queued" Pro

Causes, in the order worth checking:

  • Another job is running against the same instance. The queue deliberately grants one running job per Odoo instance, so ten schedules firing at midnight can't stampede one server. It will start when its turn comes.
  • A backup of that database is already in flight. Only one is allowed at a time; asking for another gives you "A backup for this database is already running".
  • Every worker is at capacity, in which case everything is queuing, not just this one — that's the tell.

Fix. Usually waiting. A job that is genuinely orphaned recovers on its own: a running job holds a two-minute lease that its worker extends by heartbeating, so a worker that dies or loses the network has its job requeued within about two minutes, and a last-resort janitor retires any non-terminal job still sitting there after twelve hours. If a queue is stuck for longer than that, it's ours to fix — tell us.

A job is "running" but the byte counter isn't moving Pro

Cause. Odoo is still building the archive. Nothing streams until it starts sending, and on a large instance that stage can take many minutes with the counter at zero.

Fix. Wait, and watch load on the Odoo host. If it never starts moving, you'll get the timeout above — see that entry.

A job was left behind by a restart CE

Cause. CE runs backups inside the one container, so restarting it — an upgrade, a reboot — kills anything in flight.

Fix. Nothing by hand. On start CE marks orphaned jobs failed and purges the partial scratch files, then carries on with the schedule. A half-written file is never recorded as a backup.

CE: install and access

The container won't start CE

Fix first, diagnose second: docker compose logs app. The reason is almost always in the first lines. The three usual ones:

  • A missing required setting. FERNET_KEY and ADMIN_PASSWORD_HASH have no defaults; without them the app refuses to construct its settings and exits immediately.
  • A failed migration. The entrypoint runs alembic upgrade head before the web server and aborts on failure, by design — it will not serve a half-migrated database. See Upgrading OBM CE for the way back.
  • ./data isn't writable by the container. It holds the SQLite database, the archives and the generated JWT secret; if it's read-only or owned by the wrong user, nothing works.

The admin password you just set doesn't work CE

Cause. Nine times out of ten: the bcrypt hash in .env isn't single-quoted. A hash contains $ characters, Compose reads them as variable interpolation, and the value that reaches the container is a mangled hash that can never match anything.

Fix. Quote it — ADMIN_PASSWORD_HASH='$2b$12$…' — then force the reset below so the corrected hash is applied.

Locked out of the admin account CE

Fix. There is a deliberate recovery hatch:

# in .env
ADMIN_FORCE_RESET=true

docker compose up -d
docker compose logs app | grep ADMIN_FORCE_RESET
# -> ADMIN_FORCE_RESET: reset password and sessions for 'admin'

# then delete the line again

On startup this re-applies whatever ADMIN_PASSWORD_HASH currently says to the user named by ADMIN_USERNAME, re-activates the account, and revokes every live session — useful on its own if you think a session has leaked. Generate a fresh hash with scripts/hash_password.py.

Remove the line afterwards. It is one-shot by intent, not by implementation: left in place, it re-applies that same hash on every single restart, which will quietly undo any password you change from inside the app later.

Still stuck?

Pro accounts: [email protected], answered within one business day — include the job's error message verbatim and roughly when it ran, and we can usually skip a round trip. Community Edition: open a GitHub issue so the next person with the same problem finds the answer. Security reports go to e-mail either way, never to a public issue.