Summary
mxcli run --local --ensure-db times out with PostgreSQL did not become ready at 127.0.0.1:5432 within 20s on a standard non-root devcontainer (Debian/Ubuntu base image, remoteUser: vscode), even though PostgreSQL is correctly installed and the system cluster (pg_lsclusters) exists.
This reproduces on any devcontainer following the pattern mxcli init itself generates for .devcontainer/: a Debian-based image, postgresql + postgresql-client installed, remoteUser set to a non-root user with sudo scoped to (root) only (the default in mcr.microsoft.com/devcontainers/base images).
Root cause (confirmed via strace -f -e trace=execve,connect)
startLocalPostgres invokes:
execve("/usr/sbin/service", ["service", "postgresql", "start"], ...)
without any sudo prefix. Debian's /etc/init.d/postgresql unconditionally calls create_socket_directory on every start invocation (even when a cluster is already registered/stopped), which does chmod/chown on /var/run/postgresql. That requires root:
$ service postgresql start
chmod: changing permissions of '/var/run/postgresql': Operation not permitted
Since this fails silently (exit 1, no output captured, nothing written to /var/log/postgresql/*.log, no process spawned), --ensure-db falls through to its pg_isready polling loop, waits the full 20s, and reports a generic timeout with no indication of the real permission error.
This is distinct from #823 / PR #824: that fix addressed hosts with no working service manager (e.g. Arch), adding a fallback to a user-owned cluster under ~/.mxcli/postgres. Per the changelog for that fix, the fallback deliberately does not trigger when a system cluster already "owns" the requested port — so on Debian/Ubuntu (where pg_ctlcluster/service exist and a system cluster is registered) it stays on the "retained system-cluster path," which uses sudo -u postgres only for the later role/database provisioning step — never for actually starting the service.
Repro
mxcli init in a fresh repo (or the equivalent hand-rolled devcontainer: Debian base image, postgresql+postgresql-client installed, remoteUser non-root with default sudo scope).
- Open in the devcontainer (or start a fresh one) so the PostgreSQL cluster is registered but not yet started.
./mxcli run --local -p <project>.mpr --ensure-db
Expected: PostgreSQL starts and provisioning proceeds.
Actual:
Ensuring database...
Starting local PostgreSQL...
Error: ensuring database: PostgreSQL did not become ready at 127.0.0.1:5432 within 20s
Suggested fix
When service postgresql start / pg_ctlcluster ... start is attempted and the current process isn't root, prefix with sudo (mirroring the existing sudo -u postgres pattern already used for role/database provisioning on the same "system cluster" path) — or at minimum surface the underlying command's stderr/exit status instead of only reporting the generic 20s readiness timeout, the way the role-creation step already does (creating role "mendix": exit status 1 + the actual sudo error text).
Environment
- mxcli: nightly build downloaded 2026-08-28 (via
SessionStart hook auto-download)
- Base image:
mcr.microsoft.com/devcontainers/base:bookworm
- PostgreSQL: 15 (Debian package,
postgresql + postgresql-client)
remoteUser: vscode (default sudoers: vscode ALL=(root) NOPASSWD:ALL)
- Mendix project version: 11.12.2
Workaround in use
Added a postStartCommand in devcontainer.json that pre-starts the cluster as root on every container start:
"postStartCommand": "sudo pg_ctlcluster 15 main start || true"
This works because once PostgreSQL is already listening, the unprivileged service postgresql start attempt inside --ensure-db still fails internally but no longer matters — the subsequent pg_isready poll succeeds immediately. Also added a sudoers drop-in (vscode ALL=(postgres) NOPASSWD: ALL) so the later sudo -u postgres role/database provisioning step doesn't hit its own separate sudo: a password is required failure (the base image's sudoers rule only covers (root), not (postgres)).
Summary
mxcli run --local --ensure-dbtimes out withPostgreSQL did not become ready at 127.0.0.1:5432 within 20son a standard non-root devcontainer (Debian/Ubuntu base image,remoteUser: vscode), even though PostgreSQL is correctly installed and the system cluster (pg_lsclusters) exists.This reproduces on any devcontainer following the pattern
mxcli inititself generates for.devcontainer/: a Debian-based image,postgresql+postgresql-clientinstalled,remoteUserset to a non-root user withsudoscoped to(root)only (the default inmcr.microsoft.com/devcontainers/baseimages).Root cause (confirmed via
strace -f -e trace=execve,connect)startLocalPostgresinvokes:without any
sudoprefix. Debian's/etc/init.d/postgresqlunconditionally callscreate_socket_directoryon everystartinvocation (even when a cluster is already registered/stopped), which doeschmod/chownon/var/run/postgresql. That requires root:Since this fails silently (exit 1, no output captured, nothing written to
/var/log/postgresql/*.log, no process spawned),--ensure-dbfalls through to itspg_isreadypolling loop, waits the full 20s, and reports a generic timeout with no indication of the real permission error.This is distinct from #823 / PR #824: that fix addressed hosts with no working service manager (e.g. Arch), adding a fallback to a user-owned cluster under
~/.mxcli/postgres. Per the changelog for that fix, the fallback deliberately does not trigger when a system cluster already "owns" the requested port — so on Debian/Ubuntu (wherepg_ctlcluster/serviceexist and a system cluster is registered) it stays on the "retained system-cluster path," which usessudo -u postgresonly for the later role/database provisioning step — never for actually starting the service.Repro
mxcli initin a fresh repo (or the equivalent hand-rolled devcontainer: Debian base image,postgresql+postgresql-clientinstalled,remoteUsernon-root with defaultsudoscope)../mxcli run --local -p <project>.mpr --ensure-dbExpected: PostgreSQL starts and provisioning proceeds.
Actual:
Suggested fix
When
service postgresql start/pg_ctlcluster ... startis attempted and the current process isn't root, prefix withsudo(mirroring the existingsudo -u postgrespattern already used for role/database provisioning on the same "system cluster" path) — or at minimum surface the underlying command's stderr/exit status instead of only reporting the generic 20s readiness timeout, the way the role-creation step already does (creating role "mendix": exit status 1+ the actualsudoerror text).Environment
SessionStarthook auto-download)mcr.microsoft.com/devcontainers/base:bookwormpostgresql+postgresql-client)remoteUser:vscode(default sudoers:vscode ALL=(root) NOPASSWD:ALL)Workaround in use
Added a
postStartCommandindevcontainer.jsonthat pre-starts the cluster as root on every container start:This works because once PostgreSQL is already listening, the unprivileged
service postgresql startattempt inside--ensure-dbstill fails internally but no longer matters — the subsequentpg_isreadypoll succeeds immediately. Also added a sudoers drop-in (vscode ALL=(postgres) NOPASSWD: ALL) so the latersudo -u postgresrole/database provisioning step doesn't hit its own separatesudo: a password is requiredfailure (the base image's sudoers rule only covers(root), not(postgres)).