Skip to content

Java action writer emits legacy MicroflowActionInfo with null ImageData, crashing Studio Pro export/upgrade #656

@dimenus

Description

@dimenus

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:

  1. $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.)
  2. 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.
  3. 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/.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions