Skip to content

Commit 4788684

Browse files
authored
Merge pull request #109 from engalar/fix/bson-compat
fix: align BSON properties with Mendix schema for mx diff compatibility
2 parents b42c20f + 530fce1 commit 4788684

File tree

4 files changed

+98
-6
lines changed

4 files changed

+98
-6
lines changed

.claude/skills/debug-bson.md

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ This skill provides a systematic workflow for debugging BSON serialization error
55
## When to Use This Skill
66

77
Use when encountering:
8-
- **Studio Pro crash** `System.InvalidOperationException: Sequence contains no matching element` at `MprProperty..ctor`
8+
- **Studio Pro crash** `System.InvalidOperationException: Sequence contains no matching element` at `MprObject..ctor` or `MprProperty..ctor`
9+
- **Studio Pro crash on open** with `RevStatusCache.CreateDeleteStatusItem` in stack trace
10+
- **`mx diff` crash** with "Sequence contains no matching element"
911
- **CE1613** "The selected attribute/enumeration no longer exists"
1012
- **CE0463** "The definition of this widget has changed"
1113
- **CE0642** "Property X is required"
@@ -135,8 +137,94 @@ reference/mxbuild/modeler/mx update-widgets /path/to/app.mpr
135137

136138
Templates must include both `type` (PropertyTypes schema) AND `object` (default WidgetObject).
137139

140+
## Critical: mx check vs mx diff vs Studio Pro Tolerance Levels
141+
142+
Three Mendix tools parse the same BSON but with **different strictness levels**:
143+
144+
| Tool | Extra properties | Missing properties | When used |
145+
|------|-----------------|-------------------|-----------|
146+
| `mx check` | **Tolerant** — silently skips | **Tolerant** — uses defaults | Validation |
147+
| `mx dump-mpr` | **Tolerant** — silently skips | **Tolerant** — uses defaults | Export |
148+
| `mx diff` | **STRICT** — crashes | **STRICT** — crashes | Version control diff |
149+
| Studio Pro `RevStatusCache` | **STRICT** — crashes | **STRICT** — crashes | Opening project with uncommitted changes |
150+
151+
**Key insight**: `mx check` passing does NOT mean Studio Pro can open the project. Always verify with `mx diff` when testing BSON writers.
152+
153+
**Why it matters**: Studio Pro calls `mx diff` internally during `RevStatusCache.DoRefresh()` to compare the working copy against git HEAD. Any BSON property mismatch → crash on open.
154+
155+
## Diagnostic: mx diff as Crash Reproducer
156+
157+
### Step 0: Reproduce Outside Studio Pro
158+
159+
```bash
160+
# Self-diff: is the project's BSON clean?
161+
mx diff project.mpr project.mpr output.mpr
162+
# Success = all BSON matches schema. Crash = some mxunit has bad properties.
163+
164+
# Cross-diff: compare baseline vs modified
165+
# 1. Extract baseline from git
166+
mkdir /tmp/baseline && cd project-dir && git archive HEAD -- *.mpr mprcontents/ | tar -x -C /tmp/baseline/
167+
# 2. Run diff (file names must match!)
168+
mx diff /tmp/baseline/App.mpr ./App.mpr /tmp/diff-output.mpr
169+
```
170+
171+
### Interpreting mx diff Output
172+
173+
**Detailed error** (when both sides have same-ID objects):
174+
```
175+
Objects with ID b6fc893f-... of type Settings$ServerConfiguration do not have the same properties.
176+
baseNames = ApplicationRootUrl, ConstantValues, CustomSettings, ..., Tracing;
177+
newNames = ApplicationRootUrl, ConstantValues, ...
178+
```
179+
→ Compare the two lists. Properties in `baseNames` but not `newNames` = missing in our BSON. Properties in `newNames` but not `baseNames` = extra in our BSON.
180+
181+
**Generic error** (when objects don't have matching IDs — e.g., deleted units):
182+
```
183+
Sequence contains no matching element
184+
```
185+
→ No detail given. Use the property comparison tools below.
186+
187+
### Finding the Offending mxunit File
188+
189+
Write a Go tool (or use the pattern below) to compare property keys of mxcli-written files against Studio Pro-native files of the same `$Type`:
190+
191+
```go
192+
// Walk mprcontents/, group files by $Type, compare key sets
193+
// Files with EXTRA keys (vs native files of same type) = the crash cause
194+
// Files with MISSING keys = also crash cause for mx diff
195+
```
196+
197+
The principle: for each `$Type`, ALL instances must have the **exact same set of non-$ property names**. Any deviation → crash.
198+
199+
### Version-Specific Properties
200+
201+
Some properties only exist in certain Mendix versions. Before adding a property to a BSON writer:
202+
1. Check `reference/mendixmodellib/reflection-data/` for the property definition
203+
2. Check `min_version` if present
204+
3. Test with `mx diff` self-diff on the target version
205+
206+
**Example**: `IsReusableComponent` exists in `Projects$ModuleImpl` in newer Mendix but NOT in 11.6.4. Writing it → crash.
207+
138208
## Common Error Patterns
139209

210+
### Studio Pro Crash: InvalidOperationException in MprObject..ctor (RevStatusCache)
211+
212+
**Symptom**: Studio Pro crashes on open with stack trace through `RevStatusCache.DoRefresh``CreateDeleteStatusItem``MprUnit.get_Contents``MprObject..ctor``b__2(JProperty p)`.
213+
214+
**Root cause**: `MprObject` constructor iterates each non-`$` BSON property and does a LINQ `First()` lookup against the Mendix type schema. Any property name not in the schema → `First()` fails → crash.
215+
216+
**This is triggered by**:
217+
- Any uncommitted change to `.mpr` or `mprcontents/` files
218+
- Studio Pro uses `mx diff` internally to diff working copy vs git HEAD
219+
- Even `git update-index --assume-unchanged` does NOT help — Studio Pro reads files directly, bypassing git index
220+
221+
**Diagnosis**:
222+
1. Run `mx diff baseline.mpr working.mpr output.mpr` to reproduce
223+
2. If self-diff (`mx diff a.mpr a.mpr out.mpr`) crashes, the project itself has bad BSON
224+
3. Use property comparison tool to find extra/missing keys
225+
226+
**Fix pattern**: Remove extra properties from writer, add missing properties with correct defaults (empty array `bson.A{int32(2)}` for lists, `nil` for nullable objects, `""` for strings).
227+
140228
### Studio Pro Crash: InvalidOperationException in MprProperty..ctor
141229

142230
**Symptom**: Studio Pro crashes when opening a project with `System.InvalidOperationException: Sequence contains no matching element` at `Mendix.Modeler.Storage.Mpr.MprProperty..ctor`.

sdk/mpr/writer_modules.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ func (w *Writer) serializeModule(module *model.Module) ([]byte, error) {
249249
"AppStoreVersion": module.AppStoreVersion,
250250
"AppStoreVersionGuid": "",
251251
"IsThemeModule": false,
252-
"IsReusableComponent": module.IsReusableComponent,
253252
"NewSortIndex": int64(0),
254253
}
255254
return bson.Marshal(doc)

sdk/mpr/writer_settings.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ func serializeServerConfiguration(cfg *model.ServerConfiguration) bson.M {
120120
"ExtraJvmParameters": cfg.ExtraJvmParameters,
121121
"OpenAdminPort": cfg.OpenAdminPort,
122122
"OpenHttpPort": cfg.OpenHttpPort,
123+
"CustomSettings": bson.A{int32(2)},
124+
"Tracing": nil,
123125
}
124126
if cfg.ID != "" {
125127
cfgDoc["$ID"] = idToBsonBinary(string(cfg.ID))

sdk/mpr/writer_units.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,14 @@ func (w *Writer) insertUnit(unitID, containerID, containmentName, unitType strin
7979
INSERT INTO Unit (UnitID, ContainerID, ContainmentName, TreeConflict, ContentsHash, ContentsConflicts)
8080
VALUES (?, ?, ?, 0, ?, '')
8181
`, unitIDBlob, containerIDBlob, containmentName, contentsHash)
82-
if err == nil {
83-
w.reader.InvalidateCache()
84-
w.updateTransactionID()
82+
if err != nil {
83+
// Clean up the file we just wrote — otherwise it becomes an orphan
84+
os.Remove(filePath)
85+
return err
8586
}
86-
return err
87+
w.reader.InvalidateCache()
88+
w.updateTransactionID()
89+
return nil
8790
}
8891

8992
// MPR v1: Store directly in database

0 commit comments

Comments
 (0)