Summary
Java actions created via MDL with an exposed as ... in ... clause are written with a legacy-shaped MicroflowActionInfo BSON object. Mendix Studio Pro opens and saves such projects without complaint, but any operation that re-serializes all units — export to .mpk, version upgrade, Save As — crashes with:
System.InvalidOperationException: Null value found in primitive property 'ImageDataStorage' of object of type 'Mendix.Modeler.CodeActions.MicroflowActionInfo'.
at Mendix.Modeler.Storage.Operations.UnitWriter.WriteBsonValue(BsonDataWriter writer, ICachedProperty prop, Object value) in Mendix.Modeler.Storage/Operations/UnitWriter.cs:line 146
at Mendix.Modeler.Storage.Operations.UnitWriter.WriteBsonObject(BsonDataWriter writer, IStorageObject obj) in Mendix.Modeler.Storage/Operations/UnitWriter.cs:line 75
...
at Mendix.Modeler.Operations.ProjectSaver.SaveProject(IProject project, String mprFilePath, DatabaseFormat databaseFormat, ISet`1 unitsToExclude, IProgressInfo info)
Observed with Studio Pro 10.21.1 and 11.11.0 (beta) on an MPR v2 project at Mendix 11.8.0.
Root cause
sdk/mpr/writer_javaactions.go (~line 315) builds the action info like this:
// ImageData is byte[] in Mendix; use nil when empty instead of empty string
var imageData any
if mai.ImageData != "" {
imageData = mai.ImageData
}
maiValue = bson.D{
{Key: "$ID", Value: idToBsonBinary(maiID)},
{Key: "$Type", Value: "JavaActions$MicroflowActionInfo"},
{Key: "Caption", Value: mai.Caption},
{Key: "Category", Value: mai.Category},
{Key: "Icon", Value: mai.Icon},
{Key: "ImageData", Value: imageData},
}
Three problems versus what Studio Pro 10/11 actually writes:
$Type is the legacy qualified name JavaActions$MicroflowActionInfo; current metamodel uses CodeActions$MicroflowActionInfo. (Studio Pro's type cache still resolves the legacy alias on read, which is why the project opens.)
ImageData is emitted as BSON null. Studio Pro maps it onto the primitive (binary) property ImageDataStorage, tolerates the null on read, then throws the exception above the first time UnitWriter re-serializes the unit. The fix is the opposite of the code comment: an empty binary, never null.
- The shape is outdated:
Icon no longer exists, and IconData, IconDataDark, ImageDataDark are missing.
A healthy icon-less action info as written by Studio Pro (verified against 67 instances in one project, e.g. Community Commons):
$ID: binary(16)
$Type: "CodeActions$MicroflowActionInfo"
Caption: string
Category: string
IconData: binary(0)
IconDataDark: binary(0)
ImageData: binary(0)
ImageDataDark: binary(0)
Related: parser silently strips icons
sdk/mpr/parser_javaactions.go (~line 184) only reads Icon/ImageData as strings:
ja.MicroflowActionInfo = &javaactions.MicroflowActionInfo{
BaseElement: model.BaseElement{ID: model.ID(extractBsonID(mai["$ID"]))},
Caption: extractString(mai["Caption"]),
Category: extractString(mai["Category"]),
Icon: extractString(mai["Icon"]),
ImageData: extractString(mai["ImageData"]),
}
So if mxcli ever rewrites a Java action unit that Studio Pro wrote (e.g. a marketplace module action with toolbox icons), the IconData/IconDataDark/ImageData/ImageDataDark binaries are dropped on the floor and the unit is re-written in the broken legacy shape.
Suggested fix
sdk/javaactions/javaactions.go (MicroflowActionInfo struct): replace Icon string / ImageData string with the four binary fields (IconData, IconDataDark, ImageData, ImageDataDark as []byte).
- Parser: read the four binary fields; keep tolerating the legacy
Icon/null-ImageData shape on read so broken units can be loaded and repaired.
- Writer: emit
CodeActions$MicroflowActionInfo with all four fields always present as binaries (empty []byte when unset, never null, no Icon key).
- The JavaScript action writer should be audited for the same pattern.
Recovery for already-corrupted projects
For anyone hitting the Studio Pro crash: the bad units can be repaired in place by rewriting the MicroflowActionInfo sub-document of the affected mprcontents/**/<uuid>.mxunit BSON files to the healthy shape above, then updating that unit's row in the .mpr SQLite Unit table — ContentsHash is base64(SHA-256(mxunit file bytes)) and UnitID is the filename UUID in .NET GUID little-endian layout (uuid.bytes_le). Affected units are findable with grep -rlF 'JavaActions$MicroflowActionInfo' mprcontents/.
Summary
Java actions created via MDL with an
exposed as ... in ...clause are written with a legacy-shapedMicroflowActionInfoBSON object. Mendix Studio Pro opens and saves such projects without complaint, but any operation that re-serializes all units — export to .mpk, version upgrade, Save As — crashes with:Observed with Studio Pro 10.21.1 and 11.11.0 (beta) on an MPR v2 project at Mendix 11.8.0.
Root cause
sdk/mpr/writer_javaactions.go(~line 315) builds the action info like this:Three problems versus what Studio Pro 10/11 actually writes:
$Typeis the legacy qualified nameJavaActions$MicroflowActionInfo; current metamodel usesCodeActions$MicroflowActionInfo. (Studio Pro's type cache still resolves the legacy alias on read, which is why the project opens.)ImageDatais emitted as BSON null. Studio Pro maps it onto the primitive (binary) propertyImageDataStorage, tolerates the null on read, then throws the exception above the first timeUnitWriterre-serializes the unit. The fix is the opposite of the code comment: an empty binary, never null.Iconno longer exists, andIconData,IconDataDark,ImageDataDarkare missing.A healthy icon-less action info as written by Studio Pro (verified against 67 instances in one project, e.g. Community Commons):
Related: parser silently strips icons
sdk/mpr/parser_javaactions.go(~line 184) only readsIcon/ImageDataas strings:So if mxcli ever rewrites a Java action unit that Studio Pro wrote (e.g. a marketplace module action with toolbox icons), the
IconData/IconDataDark/ImageData/ImageDataDarkbinaries are dropped on the floor and the unit is re-written in the broken legacy shape.Suggested fix
sdk/javaactions/javaactions.go(MicroflowActionInfostruct): replaceIcon string/ImageData stringwith the four binary fields (IconData,IconDataDark,ImageData,ImageDataDarkas[]byte).Icon/null-ImageDatashape on read so broken units can be loaded and repaired.CodeActions$MicroflowActionInfowith all four fields always present as binaries (empty[]bytewhen unset, never null, noIconkey).Recovery for already-corrupted projects
For anyone hitting the Studio Pro crash: the bad units can be repaired in place by rewriting the
MicroflowActionInfosub-document of the affectedmprcontents/**/<uuid>.mxunitBSON files to the healthy shape above, then updating that unit's row in the.mprSQLiteUnittable —ContentsHashisbase64(SHA-256(mxunit file bytes))andUnitIDis the filename UUID in .NET GUID little-endian layout (uuid.bytes_le). Affected units are findable withgrep -rlF 'JavaActions$MicroflowActionInfo' mprcontents/.