git:20260910.afa4742 to git:20260911.8d97e43

5 added, 0 removed. Audit A to A.

---
name: write-microflows
description: "Microflow syntax reference in MDL — every activity type, control flow, expressions, and the mistakes that fail `mxcli check`. Use before writing any CREATE MICROFLOW, and when debugging a microflow syntax error."
---
# Mendix Microflow Skill
This skill provides comprehensive guidance for writing Mendix microflows in MDL (Mendix Definition Language) syntax.
## Reference files
`SKILL.md` covers the shape of a microflow and the decisions. The detail lives
beside it, and is worth opening when you hit one of these:
- [`reference/control-flow.md`](reference/control-flow.md) — every form of `if`,
`case`, `split type`, `loop` and `while`, plus error handling (`try`/custom
handlers) and the `@position` / `@merge` / `@anchor` activity annotations.
- [`reference/data-operations.md`](reference/data-operations.md) — create, change,
commit, delete; list operations and aggregates; `retrieve` from database,
association and list; XPath navigation.
- [`reference/integration.md`](reference/integration.md) — `rest call` and
`send rest request`, legacy SOAP, calling Java actions (including the `empty`
argument and microflow-typed parameters), and file downloads.
- [`reference/pitfalls.md`](reference/pitfalls.md) — **read this when
`mxcli check` rejects something you believe is correct.** The anti-patterns, the
CE0111 duplicate-variable trap, the syntax that looks plausible and does not
parse, and the Studio Pro errors each one produces.
## When to Use This Skill
Use this skill when:
- Writing CREATE MICROFLOW statements
- Debugging microflow syntax errors
- Converting Studio Pro microflows to MDL
- Understanding microflow control flow and structure
If you're not sure whether the logic belongs in a microflow or a nanoflow, read the next section first. The mirror lives in [write-nanoflows](../write-nanoflows/SKILL.md) — keep both copies in sync.
## When to Use a Microflow vs a Nanoflow
| Scenario | Use |
|----------|-----|
| Querying the database | Microflow |
| Calling REST services or external actions | Microflow |
| Running Java actions | Microflow |
| File generation or download | Microflow |
| Transactional commits (rollback on error) | Microflow |
| Background scheduled logic | Microflow |
| Client-side form validation before save | Nanoflow |
| UI navigation and page routing | Nanoflow |
| Calling device features (GPS, phone, camera) | Nanoflow |
| Offline data access and local storage | Nanoflow |
| Calling JavaScript actions (NanoflowCommons) | Nanoflow |
| Showing progress indicators / confirmation dialogs | Nanoflow |
**Rule of thumb:** A nanoflow runs before the server call. A microflow IS the server call.
## Key Differences from Nanoflows
| Aspect | Microflow | Nanoflow |
|--------|-----------|----------|
| **Execution** | Server-side | Client-side (browser/mobile) |
| **Database access** | Full | No direct access |
| **Transactions** | Supported | Not supported |
| **Java actions** | Supported | Not supported |
| **JavaScript actions** | Not supported | Supported |
| **SYNCHRONIZE** | Not available | Available (offline sync) |
| **File downloads** | Supported | Not supported |
| **Error handling** | Full `ON ERROR` blocks + `RAISE ERROR` | Per-action `ON ERROR` supported; `RAISE ERROR` / `ErrorEvent` forbidden |
| **Offline** | Not available | Available |
| **Binary return type** | Supported | Not supported |
For nanoflow-specific authoring guidance, see [write-nanoflows](../write-nanoflows/SKILL.md).
## Microflow Structure
**CRITICAL: All microflows MUST have JavaDoc-style documentation**
```mdl
/**
* Microflow description explaining what it does
*
* Detailed explanation of the business logic, use cases,
* and any important implementation notes.
*
* @param $Parameter1 Description of first parameter
* @param $Parameter2 Description of second parameter
* @returns Description of return value
* @since 1.0.0
* @author Team Name
*/
create microflow Module.MicroflowName (
$Parameter1: type,
$Parameter2: type
)
returns ReturnType as $ReturnVariable
[folder 'FolderPath']
begin
-- Microflow logic here
return $ReturnVariable;
end;
```
### `exposed as … action` — putting a microflow in the toolbox
Studio Pro can show a microflow in its toolbox, so whoever drags it onto a flow
does not need to know it is a microflow rather than a Java action. A microflow
has **two** such entries — one for the microflow editor, one for the workflow
editor — so the clause names which:
```mdl
create microflow Module.FormatCode ($Raw: String)
returns String
exposed as microflow action 'Format code' in 'Toolbox demo'
icon 'assets/format-64.png'
icon dark 'assets/format-64-dark.png'
image 'assets/format-256.png'
exposed as workflow action 'Format code' in 'Toolbox demo'
begin
return trim($Raw);
end;
```
The icon should be a **64x64** PNG and the image **256x192**; paths resolve
against the directory of the .mdl file, so a script and its artwork travel
together. A different size is written with a warning; a
file that is not a PNG is refused.
**An omitted clause preserves what is stored — it does not clear it:**
| You write | What happens |
|---|---|
| `exposed as microflow action 'X' in 'Y'` | Caption and category from MDL; **icon and image carried** from what was stored |
| *(no clause)* | Both entries **preserved**, bitmaps included |
| `not exposed as workflow action` | Removes that one entry; the microflow entry is untouched |
| `… drop icon dark` | Clears one bitmap; the other three are untouched |
Rewriting a microflow's body must not cost it the icon a designer set in Studio
Pro, and saying nothing about the toolbox is not asking to be taken out of it.
Nothing below Studio Pro sees the difference — `mx check` reports 0 errors
either way — so the preserve rule is the only thing protecting it.
**Nanoflows and rules cannot be exposed.** Only `Microflows$Microflow` stores a
toolbox entry; the clause is refused on the other two with a message naming the
alternative. Java and JavaScript actions have one entry each and use the shorter
`exposed as 'Caption' in 'Category'` — see the `java-actions` skill.
### `@excluded` — documents excluded from the project
`@excluded` before a `create microflow` marks the document **"Exclude from project"**
(the same checkbox Studio Pro offers). The document stays in the `.mpr`, does not
build, and `show microflows` reports it in the `Excluded` column.
```mdl
@excluded
create microflow MyModule.LegacyCalc ()
returns Integer
begin
return 7;
end;
```
+ The sibling document annotation is **`@applyentityaccess`** — runs the flow under the current user's entity access rules rather than with full access, with the same absent-preserves rule and an explicit `(false)` to turn it off ([pitfalls](reference/pitfalls.md#apply-entity-access)).
+
Two rules follow, and both are enforced rather than documented-and-hoped:
- **An absent `@excluded` never un-excludes.** It means "the script does not say",
not "make this active" — so re-running a `create or modify` you wrote before the
document was excluded leaves the exclusion alone. Un-exclude in Studio Pro.
(Before #914 the rewrite cleared it, which is how a valid project ended up
failing **CE0122** — see the next rule.)
- **A name is not unique when a twin is excluded.** Mendix allows two documents of
the same name in one module as long as at most one is active — verified on
11.13.0: the excluded pair builds at 0 errors, the same pair both active is
`[error] CE0122 "Duplicate document name"`. `create or modify`, `describe` and
the other by-name lookups therefore target the **live** document; the excluded
twin is neither rewritten nor deleted.
The same applies to every document type that carries the flag — nanoflows, pages,
snippets, enumerations, queues, workflows, Java/JavaScript actions, mappings, JSON
structures, REST/OData services, image collections and the agent documents.
### FOLDER Option
Place microflows in folders for organization:
```mdl
create microflow MyModule.ACT_ProcessOrder ($Order: MyModule.Order)
returns boolean as $success
folder 'Orders/Processing'
begin
-- logic
return true;
end;
```
**Key Rules:**
- Parameters start with `$` prefix
- Return variable must be declared or used
- Every microflow must end with `return` statement
- Every body statement ends with a semicolon `;` — **required**, not optional. This
includes block terminators: `end if;`, `end loop;`, `end while;`, `end case;`.
A missing one is a parse error (`missing ';' at 'return'`), not a warning.
- Microflow ends with `/` separator
### Parameter Types
```mdl
-- Primitive types
$Name: string
$count: integer
$Amount: decimal
$IsActive: boolean
$date: datetime
-- Entity types
$Customer: Module.Entity
-- List types
$ProductList: list of Module.Product
-- Enumeration types
$status: enum Module.OrderStatus
```
## Variable Declarations
### ✅ CORRECT Syntax
```mdl
-- Primitive types with initialization
declare $Counter integer = 0;
declare $message string = 'Hello';
declare $IsValid boolean = true;
declare $Today datetime = [%CurrentDateTime%];
declare $status Enumeration(Module.OrderStatus) = Module.OrderStatus.Open;
```
> **You cannot `declare` an object (entity) variable.** `declare` becomes a
> *Create Variable* activity, which Mendix only allows to hold **primitive** types
> (String, Integer/Long, Decimal, Boolean, DateTime, Enumeration). An object type
> is rejected by Studio Pro/mxbuild with CE0053 ("Selected type is not allowed"),
> plus CE0038 ("Value required") and CE7247 on any following `set` — whether or
> not you give it an initializer. `mxcli check` now flags it as **MDL043**. There
> is **no** "empty object variable" activity. Get objects from one of these:
> - a microflow **parameter**: `create microflow M.Save ($Product: Test.Product) ...`
> - a **retrieve**: `retrieve $Product from Test.Product where Code = $c limit 1;`
> - a **create object**: `$Product = create Test.Product (Name = $n);`
> - a **loop iterator**: `loop $Product in $Products ...`
> **You cannot `declare` a list either.** Same *Create Variable* restriction —
> Studio Pro rejects a list with CE0053/CE0038, and `mxcli check` flags it as
> **MDL040**. Get lists from:
> - a microflow **parameter**: `create microflow M.Process ($Items: list of Test.Product) ...`
> - a **retrieve**: `retrieve $Products from Test.Product where IsActive = true;`
> - a **create list**: `$Products = create list of Test.Product;`
> **Decimal values into an `integer`/`long` fail CE0117.** Integer division
> (`$a div $b`) is always a Decimal even for two integers, and so are `random()`
> and the duration `*Between` functions (`secondsBetween`, `minutesBetween`,
> `hoursBetween`, `daysBetween`, `weeksBetween`). Assigning any of them straight
> to an `integer`/`long` variable fails `mx check` with **CE0117** (`mxcli check`
> now flags it as **MDL041**). Either declare the target `decimal`, or round it:
> ```mdl
> declare $Avg decimal = $Total div $Count; -- ✅ Decimal target
> declare $Whole integer = round($Total div $Count); -- ✅ rounded to Integer
> declare $Secs integer = round(secondsBetween($a,$b)); -- ✅ rounded to Integer
> declare $Bad integer = $Total div $Count; -- ❌ CE0117 / MDL041
> ```
> The `calendar*Between` functions (`calendarMonthsBetween`, `calendarYearsBetween`)
> return whole units (Integer) and are fine to assign directly.
### ❌ INCORRECT Syntax
```mdl
-- WRONG: Declaring an object/entity variable (CE0053/CE0038, MDL043)
declare $Product Test.Product; -- bare object declare is invalid
declare $Product Test.Product = $someObj; -- initialized object declare is also invalid
-- WRONG: Declaring a list variable (CE0053/CE0038, MDL040)
declare $ProductList list of Test.Product = empty; -- use a parameter, retrieve, or create list
-- WRONG: Using AS keyword (not supported in mxcli)
declare $Product as Test.Product; -- ERROR: parse error
-- WRONG: No value (CE0038, MDL061)
declare $X string; -- a Create Variable activity requires a value
-- WRONG: Missing type
declare $Counter = 0; -- Type inference not always supported
-- WRONG: Using 'OF' instead of 'of'
declare $list list of Test.Product; -- Case sensitive
```
## Operators
### Arithmetic
```mdl
$Result = $A + $B; -- Addition
$Result = $A - $B; -- Subtraction
$Result = $A * $B; -- Multiplication
$Result = $A div $B; -- Division (use 'div', not '/')
```
**Important**: Use `div` for division, NOT `/`. In a Mendix expression `/` is the
member/association separator (`$obj/Attr`), so `$A / $B` is not division —
`mxcli check` rejects it as **MDL045** (it would fail the build with CE0117).
Integer/decimal division always yields a Decimal; wrap it in `round()`/`trunc()`
for an Integer result (else **MDL041**).
### Comparison
```mdl
$A = $B -- Equals
$A != $B -- Not equals
$A > $B -- Greater than
$A >= $B -- Greater than or equal
$A < $B -- Less than
$A <= $B -- Less than or equal
$A = empty -- Check if empty/null
$A != empty -- Check if not empty
```
### Boolean Logic
```mdl
$Result = $A and $B; -- Logical AND
$Result = $A or $B; -- Logical OR
$Result = not $A; -- Logical NOT
-- Complex expressions
if $IsActive and $IsValid and $HasStock then
set $CanProcess = true;
end if;
```
### Date construction
`dateTime(...)` / `dateTimeUTC(...)` build a date from **literal numeric
constants only** — a variable or computed argument fails the build with CE0117
(`mxcli check` flags it as **MDL046**). To build a date from variables, step off
a literal anchor with `addDays()` / `addMonths()` (which *do* take variables):
```mdl
-- WRONG: variable args to dateTime() (CE0117 / MDL046)
set $D = dateTime(2026, $Month, $Day);
-- RIGHT: anchor on a literal, then step with addMonths/addDays
set $D = addDays(addMonths(dateTime(2026, 1, 1), $Month - 1), $Day - 1);
```
## Logging
```mdl
-- Log levels
log info 'Information message';
log warning 'Warning message';
log error 'Error message';
-- With node name
log info node 'OrderService' 'Processing order';
log warning node 'ValidationService' 'Invalid data detected';
-- With variables (use concatenation)
log info node 'OrderService' 'Order processed: ' + $OrderNumber;
log error node 'Service' 'Error: ' + $ErrorMessage;
```
## Special Values
```mdl
empty -- Null/empty value
[%CurrentDateTime%] -- Current date/time
[%CurrentUser%] -- Current user object
toString($value) -- Convert to string
```
> **No `randomInt`.** Mendix has no `randomInt` function. Use `random()` (returns a
> Decimal in [0,1)) and round to an integer range — e.g. a value in 0..8 is
> `round(random() * 8)`. Because `random()` is a Decimal, assigning it (or `div`,
> `secondsBetween()`, and the other duration `*Between` functions) directly to an
> `integer` variable fails the build with CE0117 — wrap it in `round()`/`floor()`/`ceil()`.
> `mxcli check` now flags an unknown expression function like `randomInt` as
> **MDL044** (with a "did you mean random()?" hint), and a Decimal assigned to an
> integer target as **MDL041** — before the build does.
>
> **MDL044 also blocks `mxcli exec`**, not just `check`: a call to a name Mendix
> has no built-in for is CE0117 at build time, so exec refuses to write the
> microflow rather than leaving you to find out from mxbuild. Two names that
> look plausible and are not real: `currentDeviceType()` and `trunc()` (use
> `round`/`floor`/`ceil`). If exec rejects a function you believe IS a Mendix
> built-in, build it once and — if mxbuild accepts it — add it to `funcTable` in
> `mdl/exprcheck/func_checker.go`; that table is the rule's only allow-list.
## Complete Example
```mdl
/**
* Process order with validation and status update.
*
* @param $OrderNumber The order to process
* @returns true when the order was found and marked processed
*/
create microflow Shop.ProcessOrder (
$OrderNumber: string
)
returns boolean as $success
begin
declare $success boolean = false;
-- Find the order (the retrieve establishes $Order — objects are never declared)
retrieve $Order from Shop.Order
where OrderNumber = $OrderNumber;
-- Validate order exists
if $Order = empty then
log warning node 'OrderService' 'Order not found: ' + $OrderNumber;
return false;
end if;
-- Validate customer association
if $Order/Shop.Order_Customer = empty then
log error node 'OrderService' 'Order has no customer';
return false;
end if;
-- Update order status
change $Order (
status = 'PROCESSING',
ProcessedDate = [%CurrentDateTime%]);
commit $Order;
-- Log success
log info node 'OrderService' 'Order processed: ' + $OrderNumber;
set $success = true;
return $success;
end;
/
```
## Calling Microflows
### ✅ CORRECT Syntax
```mdl
-- Call with result assignment (no SET keyword)
$Result = call microflow Module.ProcessOrder(Order = $Order);
-- Call without result (void microflow)
call microflow Module.SendNotification(message = $message);
-- Call with error handling
$Result = call microflow Module.ExternalService(data = $data) on error continue;
-- Run the call on a task queue (background execution). The clause goes after
-- the arguments and before any ON ERROR, and works on CALL JAVA ACTION too.
call microflow Module.ACT_Refresh() in queue Module.RefreshQueue;
call java action Module.RefreshData(Url = $Url) in queue Module.RefreshQueue;
```
**Queued calls** — the queue must already exist (`create queue Module.RefreshQueue
(Parallelism: 2)`), and a queued **Java action must `returns void`** or the build
fails with CE7038. Rewriting a microflow that has a queued call must restate the
`in queue` clause; a rewrite that omits it is refused rather than silently
dropping the binding. See `.claude/skills/mendix/scheduled-events-and-queues`.
### ❌ INCORRECT Syntax
```mdl
-- WRONG: Do NOT use SET with CALL MICROFLOW
set $Result = call microflow Module.ProcessOrder(Order = $Order); -- ERROR!
-- CORRECT: Direct variable assignment
$Result = call microflow Module.ProcessOrder(Order = $Order);
```
**Important**: The `set` keyword is for changing existing variable values, NOT for capturing microflow return values. Use direct assignment (`$var = call microflow ...`).
### Parameter Name Matching
**CRITICAL**: Parameter names in `call microflow` must **exactly match** the parameter names declared in the target microflow's signature (without the `$` prefix). A mismatch causes a build error (MxBuild) but may fail silently at MDL execution time.
```mdl
-- Target microflow declaration:
create microflow Module.SendEmail ($Recipient: string, $Subject: string)
begin ... end;
-- CORRECT: parameter names match the declaration
call microflow Module.SendEmail(Recipient = $Email, Subject = $title);
-- WRONG: parameter name does not match (EmailAddress vs Recipient)
call microflow Module.SendEmail(EmailAddress = $Email, Subject = $title); -- BUILD ERROR!
```
When calling microflows, always check the target's parameter list. Use `describe microflow Module.Name` to see the exact parameter names.
## Page Navigation
### SHOW PAGE
```mdl
-- Open page with parameter (canonical syntax)
show page Module.EditPage($Product = $Product);
-- Widget-style syntax also accepted in microflows
show page Module.EditPage(Product: $Product);
```
Both `($Param = $value)` and `(Param: $value)` syntaxes are accepted in microflow SHOW PAGE statements. Similarly, widget Action: properties accept both `show_page Module.Page(Param: $value)` and `show_page Module.Page($Param = $value)`.
### CLOSE PAGE
```mdl
close page;
```
### SHOW HOME PAGE
```mdl
show home page;
```
## Validation Checklist
Before executing a microflow script, verify:
- [ ] **No object (entity) or list is `declare`d** — objects come from a parameter, retrieve, create object, or loop iterator (MDL043); lists from a parameter, retrieve, or create list (MDL040)
- [ ] **All primitive variables are declared before SET** (`declare $var type = value;`)
- [ ] XPath association navigation uses qualified names (`Module.AssociationName`)
- [ ] All referenced attributes exist in entity definitions
- [ ] Every flow path ends with `return`
- [ ] No code appears after `return` statements
- [ ] Division uses `div` operator (not `/`)
- [ ] All entity/association names are fully qualified
- [ ] **CALL MICROFLOW parameter names exactly match target signature** (use `describe microflow` to verify)
- [ ] Microflow ends with `/` separator
- [ ] Parameters start with `$` prefix
- [ ] Proper closing for control structures (`end if`, `end loop`)
## Tips for Success
1. **Always use fully qualified names**: `Module.Entity`, `Module.Association`
2. **Test incrementally**: Create simple microflows first, then add complexity
3. **Check entity definitions**: Ensure all attributes exist before referencing
4. **Use meaningful variable names**: `$Customer` not `$c`, `$ProductList` not `$list`
5. **Comment complex logic**: Use `--` for inline comments
6. **Log important events**: Help with debugging and auditing
7. **Handle empty cases**: Check for `= empty` before using objects
8. **Use WITHOUT EVENTS appropriately**: Only when handlers must be skipped (events are on by default)
9. **Validate before executing**: Use `mxcli check script.mdl -p app.mpr --references` to catch errors
## Related Documentation
- [MDL Syntax Guide](../../docs/02-features/mdl-syntax.md)
- [OQL Syntax Guide](../../docs/syntax-proposals/OQL_SYNTAX_GUIDE.md)
- [Microflow Examples](../../examples/doctype-tests/microflow-examples.mdl)
- [Mendix Microflow Documentation](https://docs.mendix.com/refguide/microflows/)
## Quick Reference
### Variable Declaration Pattern
```mdl
declare $primitive type = value; -- Primitives (String/Integer/Decimal/Boolean/DateTime)
declare $status Enumeration(Module.Enum) = …; -- Enumerations are primitives too
-- Objects: never declare. Use a parameter, retrieve (limit 1), `$obj = create Module.Entity(...)`, or a loop iterator.
-- Lists: never declare. Use a parameter, retrieve, or `$list = create list of Module.Entity;`
```
### Object Operation Pattern
```mdl
$var = create Module.Entity (attr = value);
change $var (attr = value);
commit $var [without events] [refresh];
```
### Flow Control Pattern
```mdl
if condition then ... [else ...] end if;
loop $var in $list begin ... end loop;
return $value;
```
### XPath Pattern
```mdl
$var/attributename -- Attribute
$var/Module.AssociationName -- Association
$var/Module.AssociationName/attribute -- Chained
```
### Annotation Pattern
```mdl
@position(200, 200)
@caption 'Persist order'
@color Green
@annotation 'Note about the next activity'
commit $Order; -- Annotations apply here
```
### Annotations Are Notes, and a Note Can Be Shared
A note is a node with edges in Mendix, not a property of the activity it
documents. So `@annotation` is **repeatable** — one activity can carry several,
each its own note — and one note can be attached to several activities:
```mdl
@annotation(id: n1, text: 'both of these touch the same record')
commit $Order;
@annotation(id: n1) -- attaches THAT note, does not copy it
commit $Invoice;
```
`id:` is scoped to the flow you are writing and is not stored in the model; it
exists only so a second mention can point at the first. **Without it, two lines
with identical text are two separate notes** — mxcli never merges on text.
A note's own canvas geometry is `position: (x, y)` and `size: (w, h)`, e.g.
`@annotation(text: 'note', position: (175, -40), size: (260, 70))`. Omit them
and the note goes 100px above the activity at 200×50, stacking 60px per extra
note; DESCRIBE omits them again whenever they match, so an ordinary note keeps
the short `@annotation 'text'` form.
### Execute Database Query Pattern
```mdl
-- Static query (3-part name: Module.Connection.Query)
$Results = execute database query Module.Conn.QueryName;
-- Dynamic SQL override
$Results = execute database query Module.Conn.QueryName
dynamic 'SELECT * FROM table LIMIT 10';
-- Parameterized query (names must match query PARAMETER definitions)
$Results = execute database query Module.Conn.QueryName
(paramName = $Variable);
-- Runtime connection override
$Results = execute database query Module.Conn.QueryName
connection (DBSource = $url, DBUsername = $user, DBPassword = $Pass);
-- Fire-and-forget (no output variable)
execute database query Module.Conn.QueryName;
```
**Note:** Only `on error rollback` is supported (the default). `on error continue` is not available for this action.
### Page Navigation Pattern
```mdl
show page Module.Page($Param = $value); -- Canonical
show page Module.Page(Param: $value); -- Widget-style (also valid)
close page;
show home page;
```
### Error Handling Pattern
```mdl
call microflow ... on error continue; -- Ignore error
call microflow ... on error rollback; -- Rollback on error
call microflow ... on error { log ...; return ...; }; -- Custom handler
call microflow ... on error without rollback { ... }; -- No rollback
```
The clause goes on whichever activity may fail, not only on calls:
```mdl
declare $Name String = 'default' on error { return 'could not initialise'; };
$Name = $Other/Name on error { return 'lookup failed'; };
change $Order (Status = Shipped) on error { log error 'could not ship'; return; };
log info node 'App' 'starting' on error { return; };
show message 'saved' on error { return; };
+
+ -- BLOCKING halts the client until dismissed; after `objects`, before `on error`.
+ show message 'Hello {1}' type Warning objects [$Name] blocking;
validation feedback $Order/Total message 'must be positive' on error { return; };
show page Module.Page on error { return; };
close page on error { return; };
```
**Two limits, both reported rather than silently ignored:**
- **`on error continue` is rejected by Mendix** (CE6035) on `create`, `change`,
`commit`, `log`, `show page`, `close page`, `show message` and
`validation feedback` — **MDL076**. A custom `{ handler }` is accepted on all
of them; `continue` is fine on `declare`, `set`, `retrieve`, `delete` and
`call microflow`. Measured on 11.14.0 — note that create-*variable* and
change-*variable* accept `continue` while change-*object* does not.
- **The list-operation and aggregate forms of `set`** (`$x = head($l)`,
`$n = count($l)`) have no error handling in Mendix at all — **MDL077**.
**In a nanoflow, almost none of them take a clause at all.** `change`, `log`,
`show page`, `close page`, `show message` and `validation feedback` are CE6035
there whichever form is written; only `declare` and `set` accept one. See
`write-nanoflows`.
**End the handler.** A handler body that does not finish with `return` or `throw`
merges back into the main flow, so a variable created *after* the merge point is
out of scope on the error path — CE0108, which Studio Pro reports for the same
model. Ending the handler (as Studio Pro does when you wire it to an end event)
avoids this entirely.