a2ui-project / a2ui-project/a2ui

`UpdateDataModel` doesn't distinguish between the value-omitted and value-null cases

Abierto
#1,896 1 comentario 0 reacciones 1 asignado Reclamado por @andrewkolos Ver en GitHub
component: genui P2 status: first-line-handled type: bug
Lenguaje dominante
TypeScript
Estrellas
16.4k
Forks
1.3k
Merge medio
2 d 13 h
PR fusionados (30 d)
134

Descripción

_↴ Ported from [flutter/genui#935](https://github.com/flutter/genui/issues/935) — originally opened by [andrewkolos](https://github.com/andrewkolos) on 2026-05-27._
_Original labels: front-line-handled_

---

The v0.9 spec [distinguishes two intents on `updateDataModel`:](https://github.com/google/A2UI/blob/0e0375749bf8a940d57969d612e74f7221ad246e/specification/v0_9/json/server_to_client.json#L98)

- `"value": ` (key is present): replace the value at `path` with `x`.
- `value` key absent: remove the key at `path`.

`UpdateDataModel.fromJson` collapses both into a single `Object? value` field:

https://github.com/flutter/genui/blob/ae53cc52b35b72312f01b80eeb565163e3c869d7/packages/genui/lib/src/model/a2ui_message.dart#L214-L221

and `toJson()` drops the key with `'value': ?value`. The wire-level distinction is lost as soon as the message hits the model.

https://github.com/flutter/genui/blob/ae53cc52b35b72312f01b80eeb565163e3c869d7/packages/genui/lib/src/model/a2ui_message.dart#L235-L241

Expressed in a code example:

```dart
final message = UpdateDataModel.fromJson({
'surfaceId': 's1',
'path': '/x',
'value': null,
});
final serialized = message.toJson();
expect(serialized.containsKey('value'), isTrue); // fails. value key is dropped.
```

A deeper problem is that the data model also can't distinguish between "set to null" and "remove". There's no method to set a key to `null`. Source:

```dart
final model = InMemoryDataModel();
model.update(DataPath.root, {'x': 1, 'y': 2});
model.update(DataPath('/x'), null);
// Expected per 0.9 spec: {'x': null, 'y': 2}
// Actual: {'y': 2}
```

So even if `UpdateDataModel.fromJson` parsed the distinction correctly, the data model can't set a field to `null`:

https://github.com/flutter/genui/blob/9a748ef7c71689421e1f57bace12a734192351fa/packages/genui/lib/src/model/data_model.dart#L446-L454

I think the most practical impact of this issue would manifest in UIs that use tri-state fields (e.g. `false`, `true`, unset/reset). Not very common, but worth fixing in my opinon. To fix, I suggest splitting the setter API into a setter and a remover, then have `MessageProcessor` branch on `hasValue`.

---

### 1 comment(s) from the original issue

**[andrewkolos](https://github.com/andrewkolos)** commented on 2026-06-24:

Putting this down for now and putting on it my personal backlog. I will reassign myself if I begin looking at it again.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.