Any dynamic-typed property read (occasionally also a write) can — unpredictably, not on every call — trap with a WASM unreachable instruction inside Elements’ own runtime, aborting the entire WASM instance. The DevTools console only ever surfaces a single truncated top frame:
Fatal exception in WebAssembly!
Exception: NullReferenceException: Member access on null reference
Uncaught {stack: RuntimeError: unreachable
at AlliedHealthClient.wasm-<hash>:wasm-function[1988]:0x120163), message: unreachable}
Capturing the exception via a page-level window.addEventListener('error', ...) (a local try/catch around the JS call that triggers the WASM work does not catch it — it surfaces later than that call returns) yields the full, multi-frame stack, e.g.:
RuntimeError: unreachable
at ElementsRaiseException
at ExternalCalls.RaiseException
at DynamicHelpers.GetMember
at DynamicView.OnLayoutLoaded <-- application code, one dynamic .property read
at DynamicView.Mount's closure (fLoadHandler)
at MessageHandler.Invoke
at MessageBus.Publish
at (JS/WASM boundary, imp.env.__island_invoke)
at System.WebAssembly.InvokeMethod
at System.Reflection.MethodInfo.Invoke
The application frame at the point of the trap varies between runs of identical code with identical input — observed in DynamicView.OnLayoutLoaded (reading .status/.data/.layout off a plain JS object), LayoutEngine.RenderStatCard (via the already-“safe” __ahGetProp bridge), LayoutEngine.ParseNode (a SetMember, not a GetMember), and LoginView.HandleSubmit (reading a login-form field — code that had already succeeded dozens of times earlier in the same session). All of these call sites are reached via the app’s “hidden trigger button + onclick +=” bridge pattern (see the App.pas remarks above WireBridgeTriggers), i.e. a delegate invoked through System.Reflection.MethodInfo.Invoke across the JS/WASM boundary — every observed crash is several frames below that reflection-based invoke.
I’m told this looks like a bug in the user code, not compiler or library:
For the supplied clean repro: yes.
payload.status is absent, and the code still evaluates statusVal.ToString in an and expression, producing the null-reference exception. With Wasm exceptions disabled, that surfaces as unreachable.
That does not rule out a separate RTL/compiler defect in the original application, but this clean repro is explained and fixed in user code by guarding with assigned(statusVal) before dereferencing it.
Thanks for looking at the clean repro — the diagnosis was right in substance, though the literal fix isn’t and then: Oxygene doesn’t have that operator (confirmed by a compile error, “Expression expected”, when I tried it).
What’s actually going on: and/or between two statically-typed Boolean operands short-circuit normally, but when the operands are dynamic, both sides seem to evaluate unconditionally before combining. So (x <> nil) and (x.ToString = 'foo') still calls .ToString on a nil x — the left-hand nil check doesn’t guard anything once dynamic dispatch is involved.
I audited our app for this exact shape (a dynamic value nil-checked and dereferenced in the same and chain) and found 8 real instances across 6 files. Restructured each as a nested if instead of a compound and. One useful data point: a direct WebSocket capture of a real server response (bypassing the WASM client entirely) confirmed our success responses have no status key at all — so a status.ToString guarded only by status <> nil inside an and was firing on literally every successful message, not intermittently. That’s fixed now.
However, after fixing all of those, our list-screen crash (array-shaped payload, e.g. a response with an empty data:  ) still reproduces identically — same NullReferenceException: Member access on null reference, same call site (extracting fields off the parsed WebSocket message before it’s even dispatched to application code). I confirmed via the same direct WebSocket capture that the actual payload is well-formed — empty array, flat string columns, nothing unexpectedly null — so this isn’t an app-level bug. Looks like the array-shaped-payload marshaling issue is a second, separate bug from the and/dynamic one above.
So: two distinct issues bundled into this thread. The and/dynamic short-circuit one is fixed on our end (might be worth a doc note somewhere — it’s surprising that a dynamicand silently drops the short-circuit guarantee a plain Booleanand gives you). The array-shaped-payload one is still open and still crashes for us on every list-type screen.
Update, and a correction to my last post: after fixing the 8 and/dynamic instances I described, the array-shaped-payload crash I said was still open has not reproduced across several fresh re-tests — dashboard load, then a list screen, then dashboard again, then another list screen, all dynamic-heavy load_layout round-trips in one session. All rendered correctly or failed gracefully with an ordinary app-level error. Zero WASM exceptions.
Worth flagging the methodology issue that caused my last post to overstate confidence: our server serves the WASM bundle from a build output directory, and the browser caches AlliedHealthClient.wasm/.js independently by a ?v=... query string baked into index.html, separate from the outer page’s own cache. For a chunk of this investigation I was rebuilding and copying files correctly but re-testing against a stale cached .wasm with zero errors to signal it — the browser just silently kept running the old code. Once I confirmed via network-request inspection that the browser was actually fetching the freshly built file, the “still crashes” result from my last post turned out to be unreliable.
So: I’m no longer confident there’s a second, distinct array-marshaling bug here at all. It’s entirely possible the and/dynamic short-circuit issue was the whole story, and what looked like a second crash was just me testing an old build. Not declaring it fully resolved — this class of bug has looked fixed before and come back — but wanted to correct the record rather than leave a “still open” claim standing that I can no longer reproduce. Happy to dig further if useful for E27880.