cheatsheet-errors
Quick fixes for the MDL syntax errors that come up most: undeclared variables, wrong retrieve source, list operations, expression mistakes. Use when `mxcli check` reports an error and you want the fix
SKILL.md.claude/skills/mendix/cheatsheet-errors/SKILL.md
GitHub<!-- skill-index: generated by scripts/skill-index.py; make check-skill-index -->
<!-- /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-78 | Variable Errors |
| 79-130 | Expression Errors |
| 131-184 | Control Flow Errors |
| 185-222 | Syntax Errors |
| 223-287 | Reference Errors |
| 288-303 | Studio Pro Error Code Reference |
| 304-315 | Quick Validation Checklist |
MDL Common Errors Cheatsheet
Quick fixes for common MDL syntax errors.
Variable Errors
"Variable 'X' is not declared"
Problem: Using SET on a variable that wasn't declared.
-- WRONG
if $value > 10 then
set $IsValid = false; -- ERROR: $IsValid not declared
end if;
Fix: Add DECLARE before SET.
-- CORRECT
declare $IsValid boolean = true;
if $value > 10 then
set $IsValid = false;
end if;
"Selected type is not allowed" (CE0053)
Problem: Declaring an object (entity) or list variable. A declare maps to a
Create Variable activity, which only accepts primitives
(String/Integer/Long/Decimal/Boolean/DateTime/Enumeration). Declaring an object or
list is rejected (CE0053/CE0038, plus CE7247 on any later set) — bare or
initialized. The as keyword is also a parse error in mxcli. mxcli check flags an
object declare as MDL043 and a list declare as MDL040.
-- WRONG: declaring an object — there is no "empty object variable" (MDL043)
declare $Product Module.Product = empty;
declare $Product as Module.Product; -- AS is also a parse error
-- WRONG: declaring a list (MDL040)
declare $Products list of Module.Product = empty;
Fix: Objects and lists can't be declared — get them from a source that produces one.
-- object: a microflow parameter, a retrieve, a create, or a loop iterator
retrieve $Product from Module.Product where Code = $Code first; -- retrieve
$Product = create Module.Product (Name = $Name); -- create
-- or: create microflow M.Save ($Product: Module.Product) ... / loop $Product in $Products ...
-- list: a parameter, a retrieve, or a create list
$Products = create list of Module.Product; -- empty list to accumulate into
retrieve $Products from Module.Product where ...; -- or populate from the database
Expression Errors
"Error in expression" (CE0117)
Problem 1: Using unqualified association name in XPath.
-- WRONG: Missing module qualification
set $Name = $Order/Customer/Name;
Fix: Use fully qualified association name.
-- CORRECT: Module.AssociationName
set $Name = $Order/Shop.Order_Customer/Name;
Problem 2: Using not without parentheses — Mendix requires not(expr) form.
-- WRONG: bare not rejected by Studio Pro
if not $IsActive then ...
if not contains($Name, 'demo') then ...
Fix: Always wrap the negated expression in parentheses.
-- CORRECT: not(expr)
if not($IsActive) then ...
if not(contains($Name, 'demo')) then ...
mxcli enforces this at parse time —
not exprwithout parens is a syntax error.
"Type mismatch" in enum comparison
Problem: Comparing enumeration with string literal.
-- WRONG: String literal instead of enum value
if $task/status = 'Completed' then
Fix: Use qualified enumeration value.
-- CORRECT: Module.Enumeration.Value
if $task/status = Module.TaskStatus.Completed then
Control Flow Errors
"Activity cannot be the last object" (CE0105)
Problem: Missing RETURN statement.
-- WRONG: No RETURN
begin
declare $Result boolean = true;
log info 'Done';
-- Missing RETURN!
end;
Fix: Add RETURN statement.
-- CORRECT
begin
declare $Result boolean = true;
log info 'Done';
return $Result;
end;
"Action activity is unreachable" (CE0104), or CE0709 / CE0105
Problem: A statement that can never run — after return, raise error,
break, continue or join in the same block, after an if/else that
returns on both sides, or after a while true with no break. The code
depends on where the dead statement hangs: right after a return inside an
if it is CE0709 "Sequence flow is not accepted by origin or destination",
after a loop or an if/else it is CE0104 (plus CE0105 if it is the last
statement). mxcli check refuses all of them as MDL-FLOW05.
-- WRONG: Code after RETURN
if $value < 0 then
return false;
log info 'Negative'; -- Unreachable!
end if;
Fix: Move code before RETURN.
-- CORRECT
if $value < 0 then
log info 'Negative';
return false;
end if;
Syntax Errors
Division operator
-- WRONG: Using / for division
set $average = $Total / $count;
-- CORRECT: Use 'div' keyword
set $average = $Total div $count;
Missing END IF / END LOOP
-- WRONG: Missing END IF
if $value > 0 then
set $Positive = true;
-- Missing END IF!
-- CORRECT
if $value > 0 then
set $Positive = true;
end if;
Missing semicolons
-- WRONG: Missing semicolon
declare $count integer = 0
set $count = 1
-- CORRECT
declare $count integer = 0;
set $count = 1;
Reference Errors
"Module not found"
Problem: Using non-existent module name.
Fix: Check module exists with list modules.
"Entity not found"
Problem: Using non-existent entity name.
Fix:
- Check entity exists:
list entities in ModuleName - Use fully qualified name:
Module.EntityName
"Microflow not found"
Problem: Calling non-existent microflow.
Fix:
- Check microflow exists:
list microflows in ModuleName - Use fully qualified name:
Module.MicroflowName
"page not found" for a page the script creates further down (MDL-PAGE01)
Problem: A widget action targets a page created by a LATER statement in the
same script. Page references resolve in statement order, and exec is not
transactional — the statements before the failure are already written.
Fix:
- Move the
create pagefor the target above the page that links to it. - If two pages link to each other, no ordering works: create one without the
linking widget, then add it with
alter page ... insert. - Commit before executing a large script — recovery from a partial run is
git checkout -- App.mpr mprcontents/.
"not found" for anything else the script creates further down (MDL-ORDER01)
Problem: Same shape as MDL-PAGE01, for the other references the executor
resolves when it writes the referring document — a flow's parameter or return
type, an entity attribute's enumeration, an association endpoint, or a grant
subject. check used to pass these and exec then failed partway through.
Fix: Move the create for the named document above the statement that uses
it. Statements have no dependency order beyond this, so grouping entities and
enumerations at the top of a script avoids it entirely.
Not every forward reference is an error. These execute fine with the
definition afterwards, and are deliberately not flagged: an entity's extends
generalization, call java action, retrieve ... from, and create <entity>
inside a microflow body.
A call microflow/call nanoflow target created further down is resolved
by plain mxcli exec, which rolls the whole run back if a statement fails, so
mutually recursive flows can be written in either order (mendixlabs/mxcli#1405).
exec --continue-on-error, the REPL and -c cannot roll back and refuse it
("this run cannot be rolled back"): create the callee first, or a stub of it
first and create or modify it after the caller.
One case check cannot predict: if the document is created later by
create or modify, exec still fails when the project does not already have
it — but the script alone cannot say whether it does, so no error is reported.
Run with -p for the fullest coverage.
Studio Pro Error Code Reference
| Code | Message | Common Cause |
|---|---|---|
| CE0053 | Selected type is not allowed | Declared an object/list variable — get it from a parameter/retrieve/create/loop (MDL043 objects, MDL040 lists) |
| CE0104 / CE0709 | Activity is unreachable / Sequence flow is not accepted | Code after RETURN, BREAK, CONTINUE, JOIN, or a while true with no BREAK — check flags MDL-FLOW05 |
| CE0105 | Must end with end event | Missing RETURN |
| CE0117 | Error in expression | Unqualified association path |
| CE0117 | …on a button inside a data container | The button passes the container it sits in by its widget name ($dvGate inside dvGate). That name is a variable only for containers nested below it; use $currentObject there. Same for data-source arguments, Visible:, Editable:, DynamicClasses:, and (as CE0161) a nested list's XPath where. MDL-BUTTON02 |
| CE1571 | No argument selected for parameter | A microflow/nanoflow call with a parameter nothing fills — as a datasource: or an action:. Give it an argument (action: call nanoflow M.NF(P = $value)), or nest the widget in a data container of the parameter's type. check -p reports both |
| CE1571 | …in a control bar | A control bar is not row-scoped, so the grid's row does not fill it: pass the grid's selection ($dgOrders, with Selection: set) or move the widget into a column. $currentObject there is MDL-BUTTON01 |
| CE1834 | The 'Page' property is required | Workflow user task without a page — check flags MDL-WF01 |
| CE1876 | Single outcome must not contain activities | Single-outcome user task with a nested activity flow — check flags MDL-WF02 |
| CE6686 | Outcomes do not match the configured expression/microflow | An enumeration decision or call-microflow activity missing the empty outcome ('' -> { }) or an enumeration value — check flags the missing empty one as MDL-WF06 |
| CW0094 | Variable never used | Unused parameter/variable |
Quick Validation Checklist
Before executing MDL:
- No object or list is declared — objects come from a parameter/retrieve/create/loop (MDL043); lists from a parameter/retrieve/create list (MDL040)
- All SET targets have prior DECLARE
- Association paths are qualified:
$var/Module.Assoc/attr - Enum comparisons use
Module.Enum.Value - Every flow path ends with RETURN
- Division uses
divnot/ - All statements end with
; - IF/LOOP properly closed with END IF/END LOOP