Skip to content

ALTER PAGE corrupts/crashes on DataGrid2 customContent columns (InvalidCastException, project unloadable) #933

Description

@WouterHooglandTOF

mxcli bug: ALTER PAGE corrupts DataGrid2 ShowContentAs: customContent columns

mxcli version

nightly-20260720-88077af1 (2026-07-20T06:06:00Z)

Mendix version

10.24.20.105674

Severity

High. mxcli check (syntax + --references) and the ALTER PAGE command itself report success with no warning, but the resulting .mpr crashes mx check / mxcli docker check on load with an unhandled .NET exception (project becomes completely unloadable/unbuildable, not just the one page). A second, related symptom silently truncates/corrupts existing widget bindings (data loss in the model) with no error at all. Both are silent — nothing in mxcli's own output flags either problem; only a subsequent mx check/docker check run reveals it.

Summary

Two related defects, both triggered by ALTER PAGE (insert or replace) touching a DataGrid2 column that has ShowContentAs: customContent:

  1. Crash: any column inserted or rewritten via ALTER PAGE with ShowContentAs: customContent whose content is a plain container produces a BSON structure that mxcli describe reads back fine, but that the real Mendix loader (mx check, used internally by mxcli docker check) cannot deserialize — InvalidCastException: DivContainer -> WidgetObject. This also reproduces when re-writing (via insert/replace) columns that were originally authored in Studio Pro and worked fine before the ALTER PAGE touched them — i.e. ALTER PAGE can retroactively break pre-existing, previously-valid columns it rewrites as a side effect, not just newly-added ones.
  2. Silent ContentParams truncation: independently of the crash, when a ShowContentAs: customContent column's nested DYNAMICTEXT has a ContentParams expression referencing an association path with 2+ hops (e.g. AssocA/AssocB/Attr), writing that column via ALTER PAGE (insert or replace) silently truncates/mangles the expression — e.g. AssocA/AssocB/Attr round-trips as garbage-tokenized text, or as <unbound> (i.e. the attribute reference becomes null). No error or warning is produced; the corruption is only visible via a subsequent describe page or a full mx check.

Note: per create-page.md's own note, CREATE PAGE with ShowContentAs: customContent is documented as "mxbuild-verified, 0 errors" — the defect appears specific to the ALTER PAGE write path (insert/replace), not page creation from scratch.

Steps to reproduce (project-independent)

Minimal domain model:

create persistent entity Sample.Customer (
  Name: string(100)
);
/
create persistent entity Sample.Order (
  Number: string(50)
);
/
create association Sample.Order_Customer
from Sample.Order to Sample.Customer
type reference;
/

A page with a DataGrid2 that has at least one pre-existing customContent column bound to a 2-hop association path (this mirrors a Studio-Pro-authored page — create it with CREATE PAGE, which works fine and is mxbuild-clean):

create page Sample.Order_Overview (
  title: 'Orders',
  layout: Atlas_Core.Atlas_Default
) {
  datagrid dataGrid1 (datasource: database from Sample.Order) {
    column "Order_Customer/Name" (
      attribute: Order_Customer/Name,
      caption: 'Customer',
      ShowContentAs: customContent
    ) {
      container ctnName (designproperties: ['Spacing': ['margin-left': 'S']]) {
        dynamictext txtName (
          content: '{1}',
          contentparams: [{1} = Sample.Order_Customer/Sample.Customer/Name]
        )
      }
    }
  }
}
/

Verify this page is clean: mxcli docker check -p sample.mpr → 0 errors.

Repro 1 (crash): insert a second customContent column via ALTER PAGE:

alter page Sample.Order_Overview {
  insert after dataGrid1.Name {
    column colFlag (caption: ' ', ShowContentAs: customContent) {
      container ctnFlag (visible: [$currentObject/Order_Customer/Name != '']) {
        dynamictext txtFlag (content: '!')
      }
    }
  }
};

mxcli check/exec report success (Altered page Sample.Order_Overview). Then run:

mxcli docker check -p sample.mpr

→ crashes with System.InvalidCastException: Unable to cast object of type '...DivContainer' to type '...WidgetObject' during Loading the mpr file (before any per-page validation is even printed).

Repro 2 (silent truncation): instead of inserting, replace the pre-existing 2-hop column (or the whole datagrid dataGrid1 widget) with an MDL block containing the identical original text (byte-for-byte, copied from describe page):

alter page Sample.Order_Overview {
  replace "Order_Customer/Name" with {
    column "Order_Customer/Name" (
      attribute: Order_Customer/Name,
      caption: 'Customer',
      ShowContentAs: customContent
    ) {
      container ctnName (designproperties: ['Spacing': ['margin-left': 'S']]) {
        dynamictext txtName (
          content: '{1}',
          contentparams: [{1} = Sample.Order_Customer/Sample.Customer/Name]
        )
      }
    }
  }
};

mxcli exec reports success with no error. Then describe page Sample.Order_Overview shows the contentparams value corrupted (truncated tokens, e.g. dropping the leading Sample.Order_Customer/Sample. prefix and leaving a dangling fragment) or shown as <unbound>, and mxcli docker check then fails to load the project (InvalidOperationException/ArgumentNullException setting AttributeRef.AttributeId, i.e. the reference is now null).

Expected behaviour

ALTER PAGE insert/replace on a customContent DataGrid2 column should produce a .mpr that loads and builds cleanly in mx check, identical in effect to the same structure authored via Studio Pro or via CREATE PAGE. Multi-hop ContentParams association expressions should round-trip unchanged.

Actual behaviour (verbatim from my session)

  • After an ALTER PAGE insert adding 3 new customContent columns (each a container + dynamictext) to a pre-existing DataGrid2, mxcli check/exec reported success. mxcli docker check -p project/MIC.mpr then failed while still printing Loading the mpr file (i.e. before reaching any page-specific check), with:
    ERROR: System.InvalidCastException: Unable to cast object of type 'Mendix.Modeler.WebUI.Forms.Widgets.LayoutWidgets.DivContainers.DivContainer' to type 'Mendix.Modeler.WebUI.Forms.Widgets.CustomWidgets.WidgetObject'.
       at Mendix.Modeler.Utility.Collections.DefaultList`1.System.Collections.IList.Add(Object value) in Mendix.Modeler.Utility\Collections\List\DefaultList.cs:line 94
       at Mendix.Modeler.Storage.Operations.UnitContentsLoader.FillProperties(...)
       at Mendix.Modeler.Storage.Operations.UnitContentsLoader.ConstructObjectInternal(...)
       ... (repeats through nested FillProperties/ConstructObjectInternal/ConvertFromStorage frames) ...
       at Mendix.MxToolset.Check.CheckRunner.LoadProject(CheckOptions options)
    
  • Dropping the 3 newly-added columns (drop widget dataGrid<n>.col2, dataGrid<n>.col3, dataGrid<n>.col4) did not clear the crash — the identical InvalidCastException persisted, because a later ALTER PAGE replace <datagrid> with {...} (attempting to rewrite the whole grid, including its original, previously-untouched columns, back to their documented text) re-triggered the same cast failure on those original columns too. Only fully drop widget-ing the entire DataGrid2 (no re-insert) restored a loadable project.
  • Separately, after a replace of a single pre-existing column whose dynamictext had ContentParams: [{1} = Module.Association1/Module.Association2/Attr] (an exact copy of what describe page had shown for that same widget, previously valid), the next describe page showed the value corrupted to a short, garbled fragment (e.g. the leading Module.Association1/Module. segment dropped, leaving a dangling, unparseable tail concatenated with unrelated text from an adjacent expression), and a different column's equivalent single-hop reference came back as contentparams: [{1} = <unbound>]. mxcli docker check on that state failed during Loading the mpr file with:
    ERROR: System.InvalidOperationException: An error occurred when trying to set the 'Attribute' property of a Attribute in a Page with ID <page-guid>.
     ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
     ---> System.ArgumentNullException: Value cannot be null. (Parameter 'value')
       at Mendix.Modeler.DomainModels.Refs.AttributeRef.set_AttributeId(AttributeIdentifier value)
    
  • Both symptoms reproduced identically whether the triggering ALTER PAGE used insert or replace, and whether the ContentParams expression was written single-line or multi-line.

Workaround

None that preserves the feature. What I did to restore a loadable project: alter page Module.Page { drop widget <dataGridName> } — removed the entire DataGrid2 (not just the newly-added columns) rather than attempt further insert/replace repairs, since each repair attempt reproduced one of the two symptoms above. The page is left without its results table; restoring it requires manually re-adding the DataGrid2 in Studio Pro. Columns that do not use ShowContentAs: customContent (plain attribute-bound columns) were not observed to be affected — only customContent columns.

Diagnostic bundle

Available: yes — mxcli-diag-20260819-220247.tar.gz (workspace root). Note: the bundle's log only contains abstract execute_error lines for the failed ALTER PAGE attempts, without the full InvalidCastException/ArgumentNullException stack traces quoted above — those were captured directly from the mxcli docker check terminal output during the session and are not otherwise present in the bundle.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions