Troubleshooting¶
Symptoms you may meet on a fresh host, what causes them and what to do. GET /api/health
(curl -H "Authorization: Bearer $EASY_MXL_TOKEN" http://localhost:9700/api/health) is the
first thing to check: it tells you whether Docker is reachable, whether /proc/locks is
readable and where the TAI offset comes from.
Docker and images¶
permission denied on /var/run/docker.sock¶
Health shows Docker unreachable and the API answers 502 docker_unavailable. Run EASY MXL as
root (systemd unit) or add your user to the docker group: sudo usermod -aG docker $USER,
then log in again or newgrp docker. Check with docker info. If the daemon is simply not
running: sudo systemctl start docker.
Image pull fails¶
Behind a proxy configure the daemon as described under
Requirements (docker pull ghcr.io/cbcrc/test-generator:latest
on the host shows the raw error). The images are published for linux/amd64; on an arm64 host
Docker needs qemu-user-static / binfmt emulation. An image that does not exist yet on
ghcr.io (check the hands-on repository) has to be built from source and given a new image
in a custom catalog.
Domains and flows¶
A domain does not show up inside an app¶
The GStreamer apps list every directory under /mxl-domain that contains a domain_def.json.
A directory created by hand has none - create the domain through EASY MXL (Domains & Flows or
POST /api/domains), or add the file; such directories are flagged "no domain_def.json" in the
domain list. Also check the mount: the web apps expect the domain at /mxl-domain, the
hands-on writer / reader tools at /domain. The domain view shows the attached containers and
a copy-ready mount snippet (-v /dev/shm/mxl/domain_1:/mxl-domain -e MXL_DOMAIN=/mxl-domain).
missing domain_def.json on a domain¶
The directory exists under the domain root but has no (or an unreadable) domain_def.json, so
the apps' domain scan skips it and the launch dialog refuses to select it. Open the domain
under Domains & Flows and press Fix: create domain_def.json; EASY MXL writes a new
definition with a fresh id and the directory name as label
(POST /api/domains/<name>/repair). A valid existing file is only replaced when force is
set in the API call.
A flow shows inactive although its writer is running¶
Activity comes from /proc/locks, so EASY MXL must run on the same host as the containers; if
it runs in Docker it needs --pid=host and --cgroupns=host
(Deployment). When /proc/locks is
unreadable the status is unknown (active: null); GET /api/health reports
procLocksReadable. If the writer has crashed the flow really is inactive or stale - delete it
from the flow table.
A flow is active but has no writer container¶
The lock holder's PID could not be mapped to a container. In a containerised EASY MXL this is
the missing --cgroupns=host: in a private cgroup namespace /proc/<pid>/cgroup of other
containers' processes no longer contains the docker-<id>.scope path. A writer that runs
directly on the host (not in a container) also shows no container name.
"not on tmpfs" warning on a domain¶
The domain root is on a disk filesystem. MXL memory maps the flow files and expects RAM-backed
storage; use /dev/shm/mxl (default), mount a tmpfs at your root (see
Requirements), or on WSL 2 use the /Volumes/mxl fstab
entry from the hands-on preparation and --domain-root /Volumes/mxl.
mxl-writer cannot write: Permission denied in its logs¶
The hands-on writer and reader run as uid 1000 and need a domain directory writable by that
uid. EASY MXL creates domains as 1000:1000 mode 0775 when it runs as root; when it runs
unprivileged it cannot chown, so either run it as root or set --domain-uid/--domain-gid to
your own ids. Fix an existing domain with sudo chown -R 1000:1000 /dev/shm/mxl/domain_1.
Latency or last-write age is off by about 37 s¶
The TAI-UTC offset could not be read (no python3); GET /api/health shows taiOffsetNs and
taiSource. Install python3 or ignore it - flow status does not depend on it. See
How it works.
Launching and ports¶
Port already in use¶
For EASY MXL itself (EADDRINUSE at start) choose another port with --port. For an app, the
launch dialog checks each host port (/api/ports/check) and warns; change the host port in the
form or stop the process using it (ss -ltnp | grep 9600). If a container of the same name
already exists - typically from the hands-on docker compose stack - the launch reports
name_conflict and offers Start existing or Remove & relaunch.
HTML5 Keyer crashes at start (Chromium "Bus error" / renderer gone)¶
Chromium needs a 1 GB /dev/shm inside its container; the catalog sets shmSize: "1g".
Verify with docker inspect html5-keyer --format '{{.HostConfig.ShmSize}}' (expected
1073741824), and make sure the host has that much free memory besides the domains.
Access¶
403 origin_not_allowed / host_not_allowed¶
The browser origin or the Host header does not match the address EASY MXL is bound to
(typical behind a reverse proxy or when opening it through a DNS name while bound to
loopback). Add the public origin or name with --allowed-origins /
EASY_MXL_ALLOWED_ORIGINS (Configuration).
401 unauthorized / the UI keeps asking for a token¶
The request carries no token or a wrong one. The token is EASY_MXL_TOKEN in
/etc/default/easy-mxl (installer) or whatever you passed with -e EASY_MXL_TOKEN / --token.
The UI stores it in the browser once accepted; clear it by entering the new one when prompted.