debug-microflows

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 wro

SKILL.md

GitHub
<!-- skill-index: generated by scripts/skill-index.py; make check-skill-index -->

Find it fast

sed -n '<from>,<to>p' SKILL.md one section rather than reading the file; ./mxcli syntax <topic> answers how do I write this for a fraction of either.

lines section
26-37 Overview
38-47 When to use this skill
48-61 Prerequisites
62-81 The loop
82-101 Commands
102-132 Nanoflows (client-side)
133-149 Gotchas
150-157 Validation checklist
158-160 Microflow/nanoflow debugger (mxcli debug)
<!-- /skill-index -->

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:

    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

# 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:

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.

Microflow/nanoflow debugger (mxcli debug)

set breakpoints by name (activity resolved from the model), inspect paused flows + variables, step over/into/out, continue — against a run --local runtime. Two M2EE planes wired behind one command (admin enable/disable/status, app /debugger/ session); run --local --debug enables it at boot. Nanoflows are auto-detected (uses the nanoflow_name breakpoint param; paused nanoflows are merged from poll_events, which get_paused_microflows omits). Nanoflow LOG output is rewritten to the Client_Nanoflow node in the runtime log. and docs/11-proposals/PROPOSAL_microflow_debugger.md