Skip to content

Troubleshooting

Start with myxo check LAYOUT. It finds most of what follows, without starting anything. It reads the clients that services ask for from their source, without creating them. A client whose interface sits in a variable escapes it: a missing url or implementer then shows up in the log of a running process, as a service that keeps restarting.

The layout

Message Cause and remedy
unknown service NAME no installed package declares it. Check the entry point, then install the package again: uv sync
NAME is placed more than once a service belongs to one process. Remove it from the others
NAME is configured but not placed a [services.NAME] section with no process running it. Place it, or remove the section
the layout needs the environment variable NAME ${NAME} has no default. Set it, or write ${NAME:-default}
entry point 'a' loads service 'b' the entry point's name differs from the class's name
no process 'x' in layout (has ...) a mistyped process name for myxo serve
myxo: error: choose a process: ... the layout has several processes, so myxo serve needs one named
[services.NAME]: Object contains unknown field ... a mistyped key in that section. A wrong type reads Expected ..., with the field
FILE: unknown key KEY in [processes.NAME] a mistyped key in that section, or at the top of the layout without in
FILE: [processes.NAME]: Expected ... a value of the wrong type in that section, once the environment fills it
FILE: Expected ... - at ... a value of the wrong type elsewhere in the layout, such as [supervisor]

Services and interfaces

Message Cause and remedy
NAME is called over the network, so its process needs a url a process calls a service placed elsewhere. Give that service's process a url
no service in the layout implements API (...) no service in the layout has that interface, or a remote one doesn't declare it in the myxo.apis entry points
API: messages must be frozen Structs of immutable fields: ... a message allows mutation. Set frozen=True, and use tuples where you have lists
API.op must take exactly one msgspec.Struct argument an operation has no message, or several. An operation with no input takes an empty struct
x imports y: a must reach b through its interface, ... an import bypasses the interface, from another package or from another service's module in the same one. Import the interface module alone
a service uses the framework's events, so the layout needs a `database` the layout has no top-level database. migrate names the framework's events, jobs, schedules or cache, and check and serve say the framework's services
group G has two handlers for E two methods in one group handle one event type. Give one a group=
process P is marked free-threaded, but ... the message names the reason: the Python build, PYTHON_GIL=1, or the module whose import turned the GIL back on
S.m: no setting 'F' in its Config to take the period from @scheduled(every="F") names a field that the service's Config lacks. A field that holds no number gives is no number of seconds

SQLite and replicas

Message Cause and remedy
process P cannot run N instances on SQLite, ... replicas need PostgreSQL. Set DATABASE_URL to a postgresql:// URL
processes ... share the SQLite database ... from different hosts SQLite serves one host. Use Unix sockets on one host, or move to PostgreSQL
one machine runs one instance of each process; ... myxo up runs one of each. Export for a platform to run more
OperationalError, database is locked the writes outrun SQLite's single writer. See the rates that say when to move

The database

Symptom Cause and remedy
the migrations cannot reach the database: ... a mistyped URL, or the server is down
a migration fails on a missing database or role Myxo creates tables. The database and its user must exist
database unavailable, retrying in the log the framework's services wait for the database, and resume by themselves
no such table or relation does not exist, on a myxo_ table the migrations have not run. Run myxo migrate after adding a framework service
events never arrive the publisher's database differs from the layout's database

Running

Symptom Cause and remedy
myxo: GaveUp: NAME failed 6 times in 60s a service keeps failing. Read the tracebacks above it in the log
the server could not start; its log says why most often a port already taken. Change PORT
Unavailable: NAME is not running the service is restarting, or has not started. Handle it with retry, or a higher stage for callers in the same process
Unavailable: ... no answer within 30.0 s a slow callee, or a blocked event loop. Put the work in a job, or raise call_timeout
RemoteError the callee has a bug: its log has the traceback. With the answer is no T, the callee answered with another version of the message, as during an upgrade: run the same version on both sides
a new entry point is ignored the runtime reads the installed package. Install it again
each process takes seconds to start a user who can't write .pyc files, with no compiled bytecode. Install with --compile-bytecode
/readyz answers 404 or nothing the process has no url, so it has no listener

Exporting

Message Cause and remedy
for Kubernetes: processes.P.url must read ${MYXO_URL_P} see what the layout must read
Kubernetes pods share no files, ...: is a variable unset? DATABASE_URL was unset at the export, so the layout fell back on SQLite
Kubernetes needs the application's image (--image) give --image
name the public process 'web', or use a layout with one process the export can't tell which process serves $PORT
systemd runs one instance of each process; ... the same on Hop3. Only Kubernetes runs replicas
Hop3 cannot reduce the privileges of P; ... accept that with --without-sandbox, or use another target