Skip to content

ExpressionEvaluator.evaluate warns ONCE PER EVALUATION on a faulting ${…} — a broken prop in a 200-row list is 200 console lines per render #6444

Description

@claude

Found while censusing predicate-fault reporting for #6038. Filed unassigned; out of that card's scope (it is not a node gate).

The defect

packages/core/src/evaluator/ExpressionEvaluator.ts, evaluate() — both fault paths log unconditionally and are not deduped:

// per-part catch, multi-part templateconsole.warn(`Expression evaluation failed for: ${expr}`,error);// outer catchconsole.warn(`Failed to evaluate expression: ${expression}`,error);

Every sibling reporter in this area IS rate limited, and each records why:

  • fieldRules.tswarnPredicateFailure — deduped per (dialect, source): "a broken predicate is re-evaluated on every render/keystroke, and the point is one loud line, not a scrolling wall."
  • visibilityDiagnostic.ts — deduped per (type, key, source), for the same reason.

evaluate() is the odd one out, and it is on the hottest path of the three: SchemaRenderer calls it for every properties.* value, every props.* value and content, for every node, on every render.

Measured

On the built evaluator, evaluateCondition('${nosuchroot.x > 1}') three times in a row produced 3console.warn lines (the CEL envelope, by contrast, produced 1 for the same three calls). A single broken ${…} in a prop of a 200-row list is therefore 200 lines, and 200 more on the next render — the exact "一个列表里几百行会淹没控制台" hazard #6038's ruling names as the reason its own warning had to be rate limited.

Note on what #6038 did and did not change here

#6038 added EvaluationOptions.onFault; when a caller supplies it, these two console.warns are replaced by the passback, so the node-gate path is now deduped by the caller's reporter. Every other caller — props, content, properties — passes no onFault and still floods. The fix is to give these two sites the same one-per-source rate limit the two sibling reporters already have.

One thing to decide rather than assume: whether the dedupe should be keyed on the source text alone (matching warnPredicateFailure) — an interpolated string evaluated against many different scopes is one authoring mistake, but it is also the case that the same text can be genuinely broken in one scope and fine in another.

Related: #6038 (the onFault seam), #5926.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions