Summary
mxcli docker check silently converts an MPRv2 project to the self-contained MPRv1 storage
format. It inlines every unit into the .mpr (adds the Unit.Contents column) and deletes
the entire mprcontents/ directory. A command whose job is to check the project should not
rewrite the on-disk storage format.
The cause is the mx update-widgets step that mxcli docker check runs before mx check.
update-widgets performs the conversion; the check itself does not.
On a project under Git this is damaging: after the conversion the working tree no longer
matches the mprcontents/*.mxunit files tracked in the repository. If the project is then
opened in Studio Pro (which auto-converts back to MPRv2) or the state is committed, the
history and the on-disk format drift apart. In our case Studio Pro 11.12.1 then failed to
open the project at all, crashing in its Git version-control provider
(LibGit2RepositoryProvider.WriteBaseFile).
Environment
- mxcli v0.16.0 (darwin-arm64, macOS 15.6.1)
mx from Studio Pro 11.12.1 Beta (the bundled binary that mxcli docker check resolves
on macOS)
- Project version 11.12.1, MPRv2 storage format (
mprcontents/ present)
Reproduction
Format oracle used throughout (1 = MPRv1 self-contained, 0 = MPRv2):
sqlite3 App.mpr "SELECT COUNT(*) FROM pragma_table_info('Unit') WHERE name='Contents';"
Starting from a clean MPRv2 project (oracle returns 0, mprcontents/ populated), each step
run against an isolated copy:
- Model writes via
mxcli exec (alter page, create-or-replace page) → still v2. mxcli's
own writer preserves the storage format.
- Plain
mx check App.mpr (bundled binary, called directly) → still v2. The check is
read-only.
mx update-widgets App.mpr → v1. The oracle returns 1 and mprcontents/ is deleted.
mxcli docker check runs step 3 (as its "Updating widget definitions..." phase) before the
check, so the whole command reverts v2 → v1:
mxcli docker check -p App.mpr
# Updating widget definitions in App.mpr...
# Widget definitions updated.
# Checking project App.mpr...
# ...
# The app contains: 0 errors.
sqlite3 App.mpr "SELECT COUNT(*) FROM pragma_table_info('Unit') WHERE name='Contents';"
# 1 <- now MPRv1; mprcontents/ is gone
Impact
- Silent storage-format change from a command named
check.
- On a Git project, HEAD and the working tree diverge, which can corrupt the repository
state and (observed here) make Studio Pro unable to open the project.
- The conversion is easy to miss: the check reports 0 errors and looks successful.
Suggestions
mxcli docker check should not leave the project in a different storage format than it
found it. Either skip update-widgets, run it against a temporary copy, or convert back to
MPRv2 afterwards.
- At minimum, warn loudly when a check (or
update-widgets) is about to rewrite the storage
format, and skip it when the project is MPRv2.
- Independently,
mx update-widgets converting v2 → v1 looks like a platform-side surprise
worth raising with Mendix; but mxcli can shield users from it in the docker check flow.
Workaround
Validate with the bundled mx check directly instead of mxcli docker check:
"/Applications/Mendix Studio Pro <ver>*.app/Contents/modeler/mx" check /abs/path/App.mpr
The trade-off is that skipping update-widgets can surface CE0463 widget-definition-drift
false positives, which then need to be judged by hand. If a project has already been
reverted, reopening it in Studio Pro converts it back to MPRv2 and regenerates
mprcontents/.
Summary
mxcli docker checksilently converts an MPRv2 project to the self-contained MPRv1 storageformat. It inlines every unit into the
.mpr(adds theUnit.Contentscolumn) and deletesthe entire
mprcontents/directory. A command whose job is to check the project should notrewrite the on-disk storage format.
The cause is the
mx update-widgetsstep thatmxcli docker checkruns beforemx check.update-widgetsperforms the conversion; the check itself does not.On a project under Git this is damaging: after the conversion the working tree no longer
matches the
mprcontents/*.mxunitfiles tracked in the repository. If the project is thenopened in Studio Pro (which auto-converts back to MPRv2) or the state is committed, the
history and the on-disk format drift apart. In our case Studio Pro 11.12.1 then failed to
open the project at all, crashing in its Git version-control provider
(
LibGit2RepositoryProvider.WriteBaseFile).Environment
mxfrom Studio Pro 11.12.1 Beta (the bundled binary thatmxcli docker checkresolveson macOS)
mprcontents/present)Reproduction
Format oracle used throughout (1 = MPRv1 self-contained, 0 = MPRv2):
Starting from a clean MPRv2 project (oracle returns 0,
mprcontents/populated), each steprun against an isolated copy:
mxcli exec(alter page, create-or-replace page) → still v2. mxcli'sown writer preserves the storage format.
mx check App.mpr(bundled binary, called directly) → still v2. The check isread-only.
mx update-widgets App.mpr→ v1. The oracle returns 1 andmprcontents/is deleted.mxcli docker checkruns step 3 (as its "Updating widget definitions..." phase) before thecheck, so the whole command reverts v2 → v1:
Impact
check.state and (observed here) make Studio Pro unable to open the project.
Suggestions
mxcli docker checkshould not leave the project in a different storage format than itfound it. Either skip
update-widgets, run it against a temporary copy, or convert back toMPRv2 afterwards.
update-widgets) is about to rewrite the storageformat, and skip it when the project is MPRv2.
mx update-widgetsconverting v2 → v1 looks like a platform-side surpriseworth raising with Mendix; but mxcli can shield users from it in the
docker checkflow.Workaround
Validate with the bundled
mx checkdirectly instead ofmxcli docker check:The trade-off is that skipping
update-widgetscan surface CE0463 widget-definition-driftfalse positives, which then need to be judged by hand. If a project has already been
reverted, reopening it in Studio Pro converts it back to MPRv2 and regenerates
mprcontents/.