Repository navigation
Description
- I have searched the existing issues to make sure this bug has not already been reported.
Describe the Bug
a2ui_core's formatString prints a whole number of 2^63 or more as 9223372036854775807, the largest 64-bit integer. A bare value is wrong from 2^63 up to 1e21, and inside a list or object it's wrong with no upper limit. Below -2^63 it prints -9223372036854775808 the same way.
I ran into this comparing another evaluator's formatString output with a2ui_core's on the same data.
Steps to Reproduce
Run this with a2ui_core: 0.7.0:
import 'package:a2ui_core/a2ui_core.dart';
void main() {
final data = {
'a': 1e15,
'b': 1e20,
'c': 1e21,
'd': [1e21],
};
final context = DataContext(
DataModel(data),
BasicCatalog.v1_0().invoke,
'/',
protocolVersion: A2uiProtocolVersion.v1_0,
);
for (final key in data.keys) {
final text = context.resolveDynamicValue({
'@call': 'formatString',
'args': {'value': '\${/$key}'},
});
print('${data[key]} -> $text');
}
}Expected Behavior
The second line should show the same number, 100000000000000000000 as web_core prints it, and the last one [1e+21].
The spec says an interpolated number gets its "standard string representation", and objects and arrays are "stringified as JSON" (formatString type conversion). 9223372036854775807 is a different number. Dart's own toString() keeps the value, as the left column shows.
@a2ui/web_core 0.15.0 prints the expected lines for the same data, since its coerceToString uses String() and JSON.stringify. I also ran the Swift core's formatString at the same commit, and the Python core's _to_str cut from it, on a bare 1e20. Both keep the value, as 1e+20, so this looks specific to the Dart package.
conformance/core/ has no case for this. The type conversion case, test_expression_parser_data_type_coercion_matrix, has 98.5 as its only number.
Screenshots / Video / Logs
Output of the program:
1000000000000000.0 -> 1000000000000000
100000000000000000000.0 -> 9223372036854775807
1e+21 -> 1e+21
[1e+21] -> [9223372036854775807]
Compiled with dart compile js, the same program prints the expected lines. With dart compile wasm it prints the output above. I ran both in Node, not in a browser.
Environment Details
- OS: macOS 27.0.1
- Browser/Platform: Dart SDK 3.13.4 (VM), plus the JS and Wasm builds above in Node 26.4.0
- SDK/Package Name & Version: a2ui_core 0.7.0 from pub.dev, and
a2uimain (8bf644a). 0.3.0 to 0.6.0 print the same. - Protocol Version: v1.0. The v0.9 basic catalog gives the same result for
1e20. - Agent Framework & LLM Model: n/a
Additional Context
coerceToString turns a whole double into an integer with toInt(), which on the VM and in Wasm clamps to the 64-bit limits:
_numberToStringchecksabs() < 1e21, which still lets everything from 2^63 to 1e21 through._normalizeNumbers, used for lists and maps, has no range check.
The same conversion writes the bounds in numeric and length messages, so numeric with min: 1e20 fails with "Minimum value is 9223372036854775807."
It's a narrow range, numbers beyond about ±9.2e18, but in that range the text shows a different number and nothing reports an error.
I think the fix is to call toInt() only when the value fits in 64 bits. Past that, a bare value can use Dart's own toString() without the .0. In a list or map the value can stay a double, though jsonEncode then writes 1e20 as 100000000000000000000.0: the right number, but with the .0 that _normalizeNumbers is there to drop. Happy to open a PR with that and a regression test if that works for you.
Activity
Varun-S10 commentedon Nov 13, 2026
Hi @leoafarias, Thank you for raising the issue. We have reproduced the issue and we appreciate you have raised pr to fix the issue. The pr will be reviewed. Thank you for your patience and understanding.