Skip to content

[dart/a2ui_core] Discussion: Unresolved (null) required arguments silently bypass argumentSchema checks during reactive evaluation #4161

Open

Description

@RandalSchwartz

While building production reactive adapters on top of a2ui_core (v0.6.0) and discussing real-world Generative UI failure modes with the Flutter/Dart community, a subtle safety edge case came up around how CatalogInvokerExtension.invoke() handles missing or misspelled DataModel paths.

In lib/src/resolution/data_context.dart, CatalogInvokerExtension.invoke() validates non-null arguments against fn.argumentSchema (throwing A2uiExpressionError), which prevents type mismatches cleanly. However, _errorsOf() explicitly strips any key whose resolved value is null from schema['required'] before calling Schema.fromMap(...).validateSync(...):

/// A null argument is an unresolved value, such as a binding to data that
/// is not there yet, so it is left for the function to handle rather than
/// checked against the schema.

The Problem

While deferring validation makes sense while a surface is still streaming in initial updateDataModel payloads, it creates a silent failure trap for two common LLM errors:

  1. The model hallucinates or misspells a DataModel path (for example, {"path": "/cart/itmes/0/qty"} instead of /cart/items/0/qty).
  2. The path resolves to null indefinitely, silently bypassing required schema validation and invoking fn.execute(callArgs, context) anyway.

If a catalog function author follows common defensive tutorial patterns (such as (args['unitPrice'] as num?)?.toDouble() ?? 0.0), an invalid pricing binding silently renders $0.00 instead of surfacing an error or remaining pending.

Questions for Discussion

Should a2ui_core consider one (or a combination) of the following safeguards?

  1. Unresolved / Pending Sentinel vs. Executing: Should DataContext avoid invoking fn.execute() (or yield a distinct pending/unresolved state) when a required schema argument resolves to null, rather than forcing every FunctionImplementation author to duplicate required null-checks manually?
  2. Strict Validation Mode or Telemetry Hook: Providing an opt-in strict mode (or developer diagnostic warning) when a required binding resolves to null after the surface's initial data batch has settled, making misspelled LLM paths immediately visible in dev logs and agent feedback loops.
  3. Explicit Guidance on Throwing: Documenting on FunctionImplementation.execute() that missing required arguments should throw ArgumentError rather than falling back to defaults like 0.0, so component error boundaries catch broken paths loudly.

Activity

  1. added
    status: needs-triageauto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjs
    on Nov 11, 2026
  2. polina-c commented on Nov 12, 2026

    @polina-c
    Collaborator

    From triage bot:

    Triage suggestion:

    For humans

    Summary:
    The issue asks whether a2ui_core should stop calling a catalog function when a required argument resolves to null. Today _errorsOf drops null arguments from required before it validates, as the doc comment on invoke says. So a misspelled data path reaches the function as null, and a function that turns null into 0 shows a wrong value instead of an error.

    Why flagged for triage:
    This issue has external input but no priority label yet.

    Suggestion:
    Add status: needs-team-input. The team needs to decide whether a required argument that stays null should keep the function from running (or be reported), should only be documented on FunctionImplementation.execute, or should stay as it is, and whether the answer belongs in the specification for every core SDK. gspencergoog is the expert: they added the null exemption in #3192 and wrote 9 of the last 20 commits to dart/a2ui_core. I did not check whether the TypeScript and Python core SDKs skip null arguments the same way.

    1. Add labels: status: needs-team-input, type: feature/enhancement, component: core sdk, lang: dart

    Reply:

    Thanks for the write-up. We will discuss it with the team and follow up here.

    To adjust and apply this suggestion, run in your a2ui checkout:

    tools/internal/triage_new/triage_ui.sh https://github.com/a2ui-project/a2ui/issues/4161
    For software
    <a2ui>
    root = TriageSuggestion(
      summary="""The issue asks whether `a2ui_core` should stop calling a catalog function when a required argument resolves to null. Today [`_errorsOf`](https://github.com/a2ui-project/a2ui/blob/8bf644a37d680a227296b8c0849a7f4b328b8b73/dart/a2ui_core/lib/src/resolution/data_context.dart#L2165-L2187) drops null arguments from `required` before it validates, as the [doc comment](https://github.com/a2ui-project/a2ui/blob/8bf644a37d680a227296b8c0849a7f4b328b8b73/dart/a2ui_core/lib/src/resolution/data_context.dart#L2064-L2066) on `invoke` says. So a misspelled data path reaches the function as null, and a function that turns null into 0 shows a wrong value instead of an error.""",
      reason="""This issue has external input but no priority label yet.""",
      suggestion="""Add `status: needs-team-input`. The team needs to decide whether a required argument that stays null should keep the function from running (or be reported), should only be documented on `FunctionImplementation.execute`, or should stay as it is, and whether the answer belongs in the specification for every core SDK. `gspencergoog` is the expert: they added the null exemption in #3192 and wrote [9 of the last 20 commits](https://github.com/a2ui-project/a2ui/commits/main/dart/a2ui_core) to `dart/a2ui_core`. I did not check whether the TypeScript and Python core SDKs skip null arguments the same way.""",
      reply="""Thanks for the write-up. We will discuss it with the team and follow up here.""",
      added_labels=["status: needs-team-input", "type: feature/enhancement", "component: core sdk", "lang: dart"]
    )
    </a2ui>
    

    🤖 Agent-generated

  3. self-assigned this
    on Nov 12, 2026
  4. Varun-S10 commented on Nov 12, 2026

    @Varun-S10
    Collaborator

    Hi @RandalSchwartz, Thank you for raising the issue. We appreciate you taking the time to share your thoughts with us.
    Hi @gspencergoog, could you please take a look?

  5. removed
    status: needs-triageauto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjs
    on Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions