Skip to content

fix(pages): native ListView database source omitted client-read arrays (runtime crash) - #9

Merged
ako merged 1 commit into
mainfrom
claude/mxbuild-diagnostics-spike-emta6h
Jul 22, 2026
Merged

fix(pages): native ListView database source omitted client-read arrays (runtime crash)#9
ako merged 1 commit into
mainfrom
claude/mxbuild-diagnostics-spike-emta6h

Conversation

@ako

@ako ako commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

A page with a native ListView over a database from (XPath) datasource passed mx check but crashed the Mendix browser client on load (redirecting to login):

TypeError: Cannot read properties of undefined (reading 'length')
  at processResult
  at retrieveByXPath

The serialized Forms$ListViewXPathSource was missing the lists the client reads .length of. The pluggable Gallery/DataGrid2 database source was already correct — this bug is specific to the native ListView.

Root cause

Engine Defect
Codec (default) Forms$ListViewSearch emitted without its SearchRefs list. The codec encoder drops an empty, never-Set PartList on a fresh element unless the $Type is registered in RegisterTypeDefaultsForms$GridSortBar.SortItems was registered, but Forms$ListViewSearch was not. A bson dump showed Search: {} (empty).
Legacy Emitted a bogus Forms$ListViewSort + a Paths key (the search list was renamed SearchRefs in Mendix 7.11.0) and no Forms$GridSortBar at all — so sorting was silently dropped too.

Not a SortItems marker issue: an empty SortItems: [2] compiles fine when search is off; the crash is the absent SearchRefs.

Changes

  • mdl/backend/modelsdk/widget_write.goRegisterTypeDefaults("Forms$ListViewSearch", {MandatoryLists: []string{"SearchRefs"}}) (emits the empty marker-3 list).
  • sdk/mpr/writer_widgets_display.goserializeListViewDataSource and the empty-source fallback (now the shared emptyListViewXPathSource helper) emit Forms$GridSortBar/SortItems (mirroring SerializeCustomWidgetDataSource) + Forms$ListViewSearch/SearchRefs + ForceFullObjects; the bogus Sort/Paths keys are removed.
  • Tests: TestListViewSourceToGen_SearchRefsEmitted (codec, encode-level), TestSerializeListViewDataSource_Database + TestEmptyListViewXPathSource_Shape (legacy).
  • Repro: mdl-examples/bug-tests/listview-database-source-searchrefs.mdl; symptom row in .claude/skills/fix-issue.md.

Testing

  • mx check = 0 errors on a fresh 11.12.1 project with the fixed ListView page.
  • A Deploy build compiles the page to a valid client chunk (DatabaseObjectListProperty) with working sort.
  • Full mdl/backend/modelsdk and sdk/mpr package suites pass; go vet and gofmt clean.

Caveat: a minimal database from ListView compiles to a valid client chunk when search is off, so the exact runtime crash was not reproduced in isolation — this is the confirmed serialization defect matching the crash signature (missing SearchRefs), aligned to the metamodel, rather than a reproduced-then-fixed crash. The pluggable Gallery source is correct and unchanged.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4


Generated by Claude Code

A page with a native LISTVIEW over a `database from` (XPath) datasource passed
`mx check` but crashed the Mendix browser client at load and redirected to
login:

  TypeError: Cannot read properties of undefined (reading 'length')
    at processResult
    at retrieveByXPath

The serialized `Forms$ListViewXPathSource` was missing the lists the client
reads `.length` of:

- Codec (default engine): `Forms$ListViewSearch` was emitted without its
  `SearchRefs` list. The codec encoder drops an empty, never-Set PartList on a
  fresh element unless the $Type is registered — `Forms$GridSortBar.SortItems`
  was registered, but `Forms$ListViewSearch` was not. Register
  RegisterTypeDefaults("Forms$ListViewSearch", {MandatoryLists: ["SearchRefs"]}).
- Legacy engine: emitted a bogus `Forms$ListViewSort` and a `Paths` key (the
  search list was renamed `SearchRefs` in Mendix 7.11.0), and no
  `Forms$GridSortBar` at all — so sorting was dropped too. Rewrite
  serializeListViewDataSource (and the empty-source fallback, now the shared
  emptyListViewXPathSource helper) to mirror the pluggable
  CustomWidgetXPathSource: GridSortBar/SortItems + ListViewSearch/SearchRefs +
  ForceFullObjects.

The pluggable Gallery/DataGrid2 database source was already correct and is
unchanged.

Verified: `mx check` = 0 errors and a Deploy build compiles the page to a valid
client chunk (working sort). Tests: TestListViewSourceToGen_SearchRefsEmitted
(codec, encode-level), TestSerializeListViewDataSource_Database +
TestEmptyListViewXPathSource_Shape (legacy). Repro
mdl-examples/bug-tests/listview-database-source-searchrefs.mdl.

Note: a minimal database-from ListView compiles to a valid client chunk when
search is off, so this is the confirmed serialization defect matching the crash
signature rather than a reproduced crash; validation against the reporter's app
is pending.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
@ako
ako merged commit 2ab62ff into main Jul 22, 2026
3 checks passed
ako pushed a commit that referenced this pull request Jul 27, 2026
`placeholder:` and `onchange:` on a textbox passed check (with an
MDL-WIDGET07 "silently dropped" warning) and then vanished — DESCRIBE
showed neither. The design's live-search box degraded to a button and
the field lost its hint text. Both are standard Mendix TextBox
properties.

The pages.TextBox model already carried Placeholder/OnChangeAction and
the modelsdk (default) engine's widgetToGen already serialized them
(mirroring TextArea/DatePicker/CheckBox) — but the grammar had no
onchange:/placeholder: property, buildTextBoxV3 never populated the
model, the legacy serializeTextBox hardcoded empty values, and the two
keys weren't in the known-props list.

- Grammar: add `ONCHANGE COLON actionExprV3` + `PLACEHOLDER COLON
  STRING_LITERAL` to widgetPropertyV3 (the tokens already existed).
- Visitor: store Properties["OnChange"]/["Placeholder"]; add
  GetOnChange()/GetPlaceholder() accessors.
- Builder: buildTextBoxV3 sets tb.Placeholder (a *model.Text) and
  tb.OnChangeAction (via buildClientActionV3, reusing the button path).
- Legacy engine: serializeTextBox emits serializePlaceholderTemplate +
  serializeClientAction from the model instead of empties.
- Add OnChange/Placeholder to staticWidgetKnownProps so MDL-WIDGET07
  stops firing.

Reported from the RSS-reader build (finding #9).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 27, 2026
`DESCRIBE PAGE` omitted a textbox's placeholder and onchange even though
both are written correctly (they are in the .mxunit and the live app
honours them) — so a DESCRIBE round-trip wasn't a reliable way to confirm
the write landed (verification note on the #9 fix).

The describe read path (parseRawWidget) only read LabelTemplate and
AttributeRef for a textbox; PlaceholderTemplate and OnChangeAction were
never read back. Add Placeholder/OnChange to the rawWidget describe model,
read the placeholder via extractTextFromTemplate (same as the label) and
the onchange via a key-agnostic renderClientActionMDL — refactored out of
extractButtonAction, since OnChangeAction is the same client-action type
as a button's Action, just under a different BSON key — and emit
`Placeholder:` / `OnChange:` in the TextBox case. DESCRIBE reads raw BSON
via GetRawUnit, so one path serves both engines.

RSS-reader follow-up (verification note on #9).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 27, 2026
`DESCRIBE PAGE` of a dynamictext bound to a non-String attribute
(Integer/DateTime/…) emitted the rendered template expression:

  ContentParams: [{1} = toString($currentObject/CountAll)]

Re-applying that made mxcli treat `toString($currentObject/CountAll)` as
an attribute NAME, failing the build with CE1613 "The selected attribute
'…toString($currentObject/CountAll)' no longer exists." A string binding
round-tripped fine (bare attribute name). On the real Reader page this hit
all six non-string bindings at once.

The write side converts a non-String attribute binding to
`toString($currentObject/Attr)` (dynamictext template parameters must be
String); the describe reader emitted that Expression verbatim instead of
reversing the transform.

Unwrap the exact auto-generated forms — `toString($currentObject/<path>)`
→ `<path>`, `toString($param/<attr>)` → `$param.attr` — in
extractClientTemplateParameters, so DESCRIBE round-trips (the write side
re-derives the toString on the next apply). Any other expression (extra
text, a hand-written toString) is left untouched.

RSS-reader follow-up finding (found verifying the #9/DESCRIBE work).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 30, 2026
…ze (TraceOps #9/#10/#17)

Three page-builder defects found by the TraceOps project, each verified against
mxbuild 11.12.1 (`mx check` → 0 errors after the fix):

#9 — `dynamictext x (Content: '')` persisted as `Content: '{1}'` with no
parameters (an orphaned placeholder) → CE0720 "Place holder index 1 is greater
than 0". buildDynamicTextV3 unconditionally defaulted empty content to `{1}`.
Now empty content with no params is a literal empty template; `{1}` is only
synthesized when a parameter exists.

#10 — `dynamictext s (Content: '$318')` was treated as a variable reference and
became an unbound `{1}` param → CE0402/CE1613 ("attribute '$318' no longer
exists"). A `$` starts a variable ONLY when followed by a letter/underscore
(new isDynamicTextVariableRef / dynamicTextVariableRe); `$318` stays literal.

#17 — `listview (… PageSize: 200)` always paged at 20: the property parsed into
the AST but was ignored on write (buildListViewV3 hardcoded 20) and never read
or emitted by describe. Now the write honors GetIntProp("PageSize"), the
describe parse reads it, and the listview formatter emits a non-default value so
it round-trips.

Tests: TestBuildDynamicTextV3_{EmptyContent,DollarDigitLiteral,VariableStillBinds},
TestIsDynamicTextVariableRef, TestBuildListViewV3_PageSize. Repro
mdl-examples/bug-tests/traceops-9-10-17-dynamictext-listview.mdl. Symptom rows
added to fix-issue.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako added a commit that referenced this pull request Jul 30, 2026
fix: TraceOps findings — DYNAMICTEXT content, ListView PageSize (#9/#10/#17) + doc-comment & combobox-association follow-ups
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants