Validation Microflows Skill

SkillCommunication

Lets your agent add input validation to form pages, checking fields and showing feedback messages to users.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Validation Microflows Skill skill

About this capability

Validation microflows for new/edit pages, attribute checks, feedback messages, and conditional validation chains. Use when a form needs input validation with messages shown against the fields.

What this skill tells your AI

The instructions your AI receives, as published by mendixlabs/mxcli in .claude/skills/mendix/validation-microflows/SKILL.md and read by ahel’s review.

This skill provides guidance for creating validation microflows in MDL that validate user input on NewEdit pages and provide feedback to users.

When to Use This Skill

Use this skill when:

  • Creating validation logic for NewEdit pages
  • Implementing attribute validation with feedback messages
  • Building conditional validation chains
  • Creating action microflows that call validation microflows

Nanoflow validation: The same patterns apply to nanoflows (create nanoflow instead of create microflow). Use nanoflows for client-side validation when server roundtrips are unnecessary — validation feedback renders instantly without a network call.

The Validation Pattern

Mendix validation follows a two-microflow pattern:

  1. VAL_Entity_Action - The validation microflow that:

    • Takes an entity object as parameter
    • Validates each required field
    • Shows validation feedback on invalid fields
    • Returns a Boolean indicating overall validity
  2. ACT_Entity_Action - The action microflow that:

    • Calls the validation microflow
    • Only proceeds with save/commit if validation passes
    • Closes the page on success

MDL Syntax

VALIDATION FEEDBACK Statement

validation feedback $VariableName/attributename message 'Error message';

With template arguments (for dynamic messages):

validation feedback $VariableName/attributename message '{1}' objects [$MessageVariable];

CLOSE PAGE Statement

close page;

Or to close multiple pages:

close page 2;

Complete Example

Validation Microflow (VAL_Car_NewEdit)

/**
 * Validates a Car entity for NewEdit operations
 *
 * Performs validation on all required fields and displays
 * appropriate error messages to the user.
 *
 * @param $Car The Car entity to validate
 * @returns Boolean indicating if all validations passed
 */
create microflow MdlTemplates.VAL_Car_NewEdit (
  $Car: MdlTemplates.Car
)
returns boolean as $IsValid
folder 'OverviewPages'
begin
  -- Initialize validation flag
  declare $IsValid boolean = true;

  -- Validate Brand (required text field)
  if trim($Car/Brand) = '' then
    set $IsValid = false;
    validation feedback $Car/Brand message 'Brand is required';
  end if;

  -- Validate Model (required text field)
  if trim($Car/model) = '' then
    set $IsValid = false;
    validation feedback $Car/model message 'Model is required';
  end if;

  -- Validate Price (required, must be positive)
  if $Car/Price = empty then
    set $IsValid = false;
    validation feedback $Car/Price message 'Price is required';
  else
    if $Car/Price <= 0 then
      set $IsValid = false;
      validation feedback $Car/Price message 'Price must be greater than 0';
    end if;
  end if;

  -- Validate enumeration (required)
  if $Car/CarType = empty then
    set $IsValid = false;
    validation feedback $Car/CarType message 'Car type is required';
  end if;

  return $IsValid;
end;
/

Action Microflow (ACT_Car_NewEdit)

/**
 * Handles the Save action for Car NewEdit page
 *
 * Validates the Car, commits it if valid, and closes the page.
 *
 * @param $Car The Car entity to save
 * @returns Boolean indicating success
 */
create microflow MdlTemplates.ACT_Car_NewEdit (
  $Car: MdlTemplates.Car
)
returns boolean as $IsValid
folder 'OverviewPages'
begin
  -- Call validation microflow
  $IsValid = call microflow MdlTemplates.VAL_Car_NewEdit($param = $Car);

  -- Only save if validation passed
  if $IsValid then
    commit $Car;
    close page;
  end if;

  return $IsValid;
end;
/

Validation Patterns

Simple Required Field Validation

if trim($entity/TextField) = '' then
  set $IsValid = false;
  validation feedback $entity/TextField message 'This field is required';
end if;

Numeric Range Validation

if $entity/Amount != empty then
  if $entity/Amount < 0 or $entity/Amount > 1000 then
    set $IsValid = false;
    validation feedback $entity/Amount message 'Amount must be between 0 and 1000';
  end if;
end if;

Enumeration Required Validation

if $entity/status = empty then
  set $IsValid = false;
  validation feedback $entity/status message 'Status is required';
end if;

Enumeration Value Comparison

IMPORTANT: When comparing enumeration values, use the fully qualified enumeration value, NOT a string literal.

-- CORRECT: Use fully qualified enumeration value
if $task/TaskStatus = Module.TaskStatus.Completed then
  -- Task is completed
end if;

if $task/TaskStatus != Module.TaskStatus.Cancelled then
  -- Task is not cancelled
end if;

-- WRONG: Do NOT use string literals for enumeration comparison
-- IF $Task/TaskStatus = 'Completed' THEN  -- This is incorrect!

Conditional Validation Based on Enumeration

-- Validate CompletedDate only when status is Completed
if $task/TaskStatus = Module.TaskStatus.Completed then
  if $task/CompletedDate = empty then
    set $IsValid = false;
    validation feedback $task/CompletedDate message 'Completed date is required';
  end if;
end if;

-- Validate DueDate for active (non-completed, non-cancelled) tasks
if $task/TaskStatus != Module.TaskStatus.Completed and $task/TaskStatus != Module.TaskStatus.Cancelled then
  if $task/DueDate = empty then
    set $IsValid = false;
    validation feedback $task/DueDate message 'Due date is required for active tasks';
  end if;
end if;

Date Validation

if $entity/StartDate != empty and $entity/EndDate != empty then
  if $entity/EndDate < $entity/StartDate then
    set $IsValid = false;
    validation feedback $entity/EndDate message 'End date must be after start date';
  end if;
end if;

Dynamic Message with Template Arguments

-- Build validation message with dynamic content
declare $ValidationMessage string = '';
if $entity/value < $entity/MinValue then
  set $ValidationMessage = 'Value must be at least ' + toString($entity/MinValue);
end if;
if $entity/value > $entity/MaxValue then
  set $ValidationMessage = if trim($ValidationMessage) = ''
    then 'Value must be at most ' + toString($entity/MaxValue)
    else $ValidationMessage + '. Value must be at most ' + toString($entity/MaxValue);
end if;

if trim($ValidationMessage) != '' then
  set $IsValid = false;
  validation feedback $entity/value message '{1}' objects [$ValidationMessage];
end if;

Association Validation

-- Validate that an association is set
if $Order/Order_Customer = empty then
  set $IsValid = false;
  validation feedback $Order/Module.Order_Customer message 'Customer is required';
end if;

Implementation Checklist

When implementing validation microflows:

  1. Initialize the validation flag: Always start with declare $IsValid boolean = true;

  2. Declare all variables before using SET: You must use declare before set for primitive variables. Parameters are automatically available but local variables require declaration.

  3. Validate all required fields: Check each attribute that needs validation

  4. Set flag to false on error: set $IsValid = false; before showing feedback

  5. Show clear error messages: Use validation feedback with descriptive messages

  6. Return the validation flag: End with return $IsValid;

  7. Handle nullable fields: Check for empty before validating nullable fields

  8. Use appropriate validation order: Validate presence before other constraints

Important: The script executor validates that all variables used with set are declared. If you use set $Var = ... without a prior declare $Var type = ..., you will receive an error like:

variable '$Var' is not declared. use declare $Var: <type> before using set

Files Modified

This feature is implemented in:

  • mdl/grammar/MDL.g4 - ANTLR4 grammar with VALIDATION FEEDBACK tokens
  • mdl/ast/ast_microflow.go - AST type definitions (MfValidationFeedbackStmt)
  • mdl/visitor/visitor_microflow_statements.go - ANTLR listener to build AST
  • mdl/executor/cmd_microflows_builder.go - Flow builder with variable validation
  • mdl/executor/cmd_microflows_show.go - DESCRIBE formatter for MDL output
  • mdl/backend/modelsdk/microflow_write.go - BSON serialization for ValidationFeedbackAction
  • sdk/microflows/microflows_actions.go - ValidationFeedbackAction struct

Validation rules (CREATE VALIDATION RULE)

binds a regex or a range to one attribute — create validation rule for Mod.Entity.Attr regex Mod.Pattern feedback '…'. The rule is anonymous and entity-scoped, so the statement names the attribute; re-running it replaces the rule of the same type and leaves the attribute's others alone. Unlocked by a STORAGE-NAME OVERRIDE in modelsdk/gen: it bound RegularExpression where Studio Pro stores RegExIdentifier, and the control (same script, key reverted) fails CE0135 "No regular expression specified" while the fixed one is 0 errors on mxbuild 11.13 with RegExIdentifier on disk. Range bounds are inclusive and map to Mendix's only three kinds (from X to Y/from X/to Y → Between/GreaterThanOrEqualTo/SmallerThanOrEqualTo); there is no strict </>, and the old grammar's forms for it — plus an EXPRESSION rule type Mendix does not have and an inline regex literal — were removed, having never had a visitor or handler. Required/Unique stay attribute constraints (not null error '…' / unique error '…'), not a second spelling here. Rewriting an entity carrying MaxLength or EqualsTo is refused on both engines rather than silently downgraded to Required; that round trip was lossy and mx check stayed green, because a Required rule is valid. Both engines carry each rule's payload on READ (ruleInfoFromGen / parseValidationRuleInfo), which is what makes the refusal narrow instead of covering all of RegEx and Range — and what lets a range bounded by another attribute survive a rewrite even though MDL cannot author one (describe entity marks it with a comment rather than rendering it wrong). A rule whose payload did not survive the read is refused as firmly as an unknown type: a bare RuleInfo of the right $Type constrains nothing, which is the same silent downgrade wearing the right name

Signals

GitHub stars
122
Forks
49
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
validation-microflows
Source
github.com/mendixlabs/mxcli