debug-microflows · git:20260821.ff81a24 · 2026-08-21 · sha256 be00b36de6a79cce
debug-microflows git:20260821.ff81a24A
Immutable. This exact content is served forever at /api/v1/blob/be00b36de6a79cce.
--- name: debug-microflows description: "Drive the Mendix runtime's microflow and nanoflow debugger from the command line with `mxcli debug` — breakpoints by name, variable inspection, step and continue. Use when a microflow produces the wrong result and reading it is not enough." --- # Debug Microflows — `mxcli debug` ## Overview `mxcli debug` drives the Mendix runtime's **microflow debugger** from the command line: set breakpoints **by name**, inspect a paused microflow's variables, and step/continue — against an app started by `mxcli run --local`. It is the headless counterpart to Studio Pro's debugger, so you can debug a server-side microflow without leaving the warm loop. mxcli is uniquely able to offer breakpoints **by name** because it owns both halves: the admin password + app URL (from `run --local`) and the activity model GUIDs (from the `.mpr`). You never deal with raw GUIDs. ## When to use this skill - A page action throws or misbehaves and you need to see *where* in a microflow it goes wrong, with the in-scope variables. - You want to confirm a microflow takes the branch/value you expect. For a server **stack trace / `LOG` output** (not stepping), you usually just want the runtime log — see `run-local` (`--runtime-log`). Use the debugger when you need to **pause and inspect** live execution. ## Prerequisites - The app running under `mxcli run --local` (Mendix 11.x). - Start it with **`--debug`** so the debugger is enabled and a session is ready: ```bash mxcli run --local -p app.mpr --debug ``` `--debug` alone does **not** change runtime behaviour — nothing pauses until you set a breakpoint. It caches a debug session token under `<projectDir>/.mxcli/` so the `mxcli debug` commands below (run from another terminal, **same `-p`**) work immediately, with no separate `mxcli debug enable`. ## The loop ```bash # terminal 1: app + debugger mxcli run --local -p app.mpr --debug # terminal 2: find the activity, break on it by name mxcli debug activities Sudoku.ACT_Hint -p app.mpr mxcli debug break Sudoku.ACT_Hint --activity 'Retrieve' -p app.mpr # now trigger the microflow in the browser — the request pauses. Then: mxcli debug paused -p app.mpr # which flow is paused + its variables mxcli debug inspect Game -p app.mpr # one variable in detail mxcli debug step over -p app.mpr # over | into | out mxcli debug continue -p app.mpr # resume (the browser request completes) # when done — ALWAYS: mxcli debug disable -p app.mpr ``` ## Commands | Command | What it does | |---------|--------------| | `mxcli debug status` | Is the debugger on? How many microflows are paused? | | `mxcli debug enable` / `disable` | Turn the debugger on/off (use `--debug` on `run --local` instead of `enable` for the warm loop) | | `mxcli debug activities <Module.Flow>` | List a microflow's activities with the object IDs you can break on | | `mxcli debug break <Module.Flow> --activity <#n\|caption> [--if <expr>]` | Set a breakpoint, resolved by name (`--if` = conditional) | | `mxcli debug unbreak <Module.Flow> --activity <#n\|caption>` | Clear a breakpoint | | `mxcli debug breaks` | List the breakpoints mxcli has set this session (name → object ID) | | `mxcli debug paused` | Show paused microflows + full state (variables) | | `mxcli debug inspect <var> [--list] [--flow <debug_id>]` | Inspect one variable of a paused flow (`--list` for a list variable → `get_list`) | | `mxcli debug step [over\|into\|out] [--flow <debug_id>]` | Advance one step (default `over`) | | `mxcli debug continue [--all]` | Resume the paused flow (or all with `--all`) | Selecting an activity: `--activity '#2'` (the index from `activities`) or a caption substring like `--activity 'Retrieve'` (must match exactly one, case- insensitive). Selecting a paused flow: `--flow <debug_id>` (from `paused`); with a single paused flow it is auto-selected. ## Nanoflows (client-side) `mxcli debug` works for **nanoflows** too — `break`/`activities`/`unbreak` auto-detect whether `Module.Flow` is a microflow or a nanoflow and set the breakpoint the right way (a nanoflow needs the `nanoflow_name` param; the wrong key NPEs the runtime — mxcli handles this for you). Break by name exactly as for a microflow: ```bash mxcli debug break Sudoku.NF_ToggleNotes --activity 'Change' -p app.mpr ``` A paused **nanoflow** does not appear in `get_paused_microflows` — it surfaces only in the runtime's `poll_events`. `mxcli debug paused` (and `step`/`inspect`/`continue`) merge both sources, so a paused nanoflow shows up with its `debug_id` like any other; its variables are in the "Client events (poll_events)" section of `paused`. Symptom of a paused nanoflow **without** mxcli: a frozen browser, the console logging "Starting execution" but never "Finished", and `mxcli debug status` showing `client_connected: true`. **Nanoflow `debug_id` is single-use.** Unlike a microflow (stable id), a nanoflow gets a **new** `debug_id` after every step — the old one is invalidated. Because each `mxcli debug` command re-reads the current state, just let `step`/`inspect`/`continue` **auto-resolve** the flow (don't pass `--flow`): a bare `mxcli debug step over` picks up the fresh id each time. Reusing a `--flow <debug_id>` copied from an earlier `paused` will fail on the second nanoflow step with "could not find … in debug with id". For **nanoflow log output**, see `write-nanoflows` — the runtime rewrites the log node to `Client_Nanoflow`, so grep `runtime.log` for `Client_Nanoflow`, not your node name. ## Gotchas 1. **A breakpoint pauses whoever hits it — the browser included.** The triggering request hangs until `continue` (or `disable`). This is normal; just don't walk away from a paused session. 2. **Always finish with `mxcli debug disable`.** `run --local --debug` disables it for you on shutdown, but if you enabled it by hand, turn it off by hand. 3. **Use the same `-p` everywhere.** The session token and breakpoint record live under `<projectDir>/.mxcli/`; a different `-p` (or none) looks in a different place and won't see the session `run --local --debug` started. 4. **Conditions are Mendix expressions** (`--if '$Game/Solved = false'`), same syntax as a Studio Pro conditional breakpoint. 5. **Overriding the target runtime:** `--app-url`, `--admin-port`, `--admin-pass`, `--debug-pass` (or `MXCLI_APP_URL` / `MXCLI_ADMIN_PASS` / `MXCLI_DEBUG_PASS`) default to a `run --local` runtime; set them to debug a differently-configured or remote runtime. ## Validation checklist - [ ] App started with `mxcli run --local --debug`. - [ ] `mxcli debug status` shows `enabled`. - [ ] `mxcli debug activities <Module.Flow>` lists the activity you want. - [ ] After triggering the flow, `mxcli debug paused` shows it with variables. - [ ] Finished with `mxcli debug disable`.