Flux version
v2.13.2
Livewire version
v4.2.4
Tailwind version
v4.2.4
Browser and Operating System
Samsung Internet 29.0 (Android 10)
What is the problem?
User-visible behavior: Users on <flux:time-picker time-format="24-hour"> with (Hebrew page locale) experience an unhandled JavaScript error during normal interaction with the picker (focus → blur on the hour input, or keyboard navigation). The error reaches the browser's global handler and the picker stops responding.
Error thrown:
Error: Invalid time string: 16:27 לפנה״צ
(The exact prefix varies — 16:27, 21:19, 09:49, etc. — and the meridiem is either לפנה״צ (AM) or אחה״צ (PM), depending on the picker's selected hour.)
Why this is unexpected: The component is explicitly configured with time-format="24-hour". The documented contract is that no meridiem should be involved at all — neither displayed nor parsed — so an "Invalid time string" containing a day-period substring shouldn't be reachable. In practice on the affected browser it is reachable.
Where it surfaces: processTime() in UITimePickerTrigger reads this.meridiemInput?.value and passes the value to getTime() → convertTimeStringTo24HourFormat(). The vendor regex /^(\d{1,2}):(\d{2})(?:\s*(am|pm|AM|PM))?$/i rejects any non-ASCII meridiem and throws.
Impact: The error is unhandled at the runtime level — the action promise rejects, Sentry captures it under auto.browser.global_handlers.onerror, and the user is left with a non-functional time picker. In our production deployment this resulted in 6 recorded events from real users over ~2 weeks (likely undercount, since only those whose sessions still had Sentry connectivity made it through).
Configuration that triggers it: time-format="24-hour" on the component, page locale that produces a non-ASCII dayPeriod from Intl.DateTimeFormat (he, and likely others — ar, zh, etc., though we haven't observed those in production).
Code snippets to replicate the problem
Minimal Blade setup that exhibits the bug in production:
{{-- layouts/app.blade.php (or any layout) --}}
<!DOCTYPE html>
<html lang="he">
<head>
<meta charset="utf-8">
@livewireStyles
</head>
<body>
<livewire:time-picker-repro />
@livewireScripts
{!! app('flux')->scripts() !!}
</body>
</html>
{{-- resources/views/livewire/time-picker-repro.blade.php --}}
<div>
<flux:time-picker
wire:model.live="t"
type="input"
time-format="24-hour"
/>
</div>
// app/Livewire/TimePickerRepro.php
<?php
namespace App\Livewire;
use Livewire\Component;
class TimePickerRepro extends Component
{
public ?string $t = null;
public function render()
{
return view('livewire.time-picker-repro');
}
}
Open the page on Samsung Internet 29.0 / Android 10 (or any browser exhibiting the boot-time race). Focus the hour input, type/scroll any value, blur. The console throws Invalid time string: HH:MM .
Force-trigger in any browser (proves the regex throws on a locale day-period):
This bypasses the boot-time race and directly exercises the broken parser. Useful for verifying the fix in CI without needing the affected device:
// In DevTools on any page, with livewire/flux-pro 2.13.x loaded:
const trigger = document.querySelector('ui-time-picker-trigger');
// Force a Hebrew meridiem regardless of how boot() resolved:
const fakeMeridiem = document.createElement('input');
fakeMeridiem.value = 'לפנה״צ';
trigger.meridiemInput = fakeMeridiem;
trigger.hourInput.value = '16';
trigger.minuteInput.value = '27';
trigger.processTime();
// → Uncaught Error: Invalid time string: 16:27 לפנה״צ
// at convertTimeStringTo24HourFormat
// at getTime
// at processTime
Standalone reproducer for the regex itself (no Flux needed):
This is the exact line that throws once a non-ASCII meridiem reaches the parser:
// Copied verbatim from flux.module.js (livewire/flux-pro 2.13.2):
function convertTimeStringTo24HourFormat(time) {
let match = time.trim().match(/^(\d{1,2}):(\d{2})(?:\s*(am|pm|AM|PM))?$/i);
if (!match) throw new Error(`Invalid time string: ${time}`);
// ...
}
convertTimeStringTo24HourFormat('16:27 לפנה״צ'); // throws
convertTimeStringTo24HourFormat('17:02 אחה״צ'); // throws
convertTimeStringTo24HourFormat('16:27 AM'); // ok
The regex's optional capture group only matches am|pm (case-insensitive ASCII). Any locale that produces a non-ASCII dayPeriod from Intl.DateTimeFormat(locale, { hour12: true }) — Hebrew, Arabic, Chinese, Japanese, Korean, etc. — will trigger this if it ever reaches the parser.
Screenshots/ screen recordings of the problem
Here's an honest block for that section — since the bug is on a device class we don't physically have, we can't produce a direct recording. Acknowledge that and substitute the evidence we do have:
Screenshots / screen recordings
We do not have a direct screen recording — the bug is reproducible only on Samsung Internet 29.0 / Android 10 with a Hebrew system locale, which we don't have physical access to. All affected users are in production.
Substituting the evidence we have:
Production console error (as captured by Sentry across 6 events):
Uncaught Error: Invalid time string: 16:27 לפנה״צ
at convertTimeStringTo24HourFormat (flux.min.js)
at getTime (flux.min.js)
at processTime (flux.min.js)
at HTMLInputElement.<anonymous> (flux.min.js)
How do you expect it to work?
With time-format="24-hour" explicitly set, the picker should treat the meridiem concept as completely off — neither rendered, nor read, nor parsed — regardless of or browser-specific timing of when picker.config.timeFormat becomes available.
Specifically:
No JavaScript errors should reach the global handler during any interaction with the picker, on any browser, with any page locale.
The picker should accept "HH:mm" input and emit "HH:mm" to wire:model, with no AM/PM logic involved at any point in the data path.
The fact that Intl.DateTimeFormat(locale, { hour12: true }) returns a non-ASCII dayPeriod for some locales should be irrelevant when time-format="24-hour" is configured. (Or, ideally, irrelevant in the 12-hour case too — the parser should accept locale day-periods or only operate on the internal 24-hour value — but that's a larger change.)
In other words, the behavior on Samsung Internet 29.0 with Hebrew locale should be the same as it is today on Chrome desktop with English locale: the picker works, no console errors, no Sentry events.
Smallest possible fix that achieves this: call this.use24HourFormat() lazily inside processTime() (or in the meridiem-read path) instead of relying on the boot-time decision in this.meridiemInput = null. Any browser timing race in boot() then stops mattering.
Please confirm (incomplete submissions will not be addressed)
Flux version
v2.13.2
Livewire version
v4.2.4
Tailwind version
v4.2.4
Browser and Operating System
Samsung Internet 29.0 (Android 10)
What is the problem?
User-visible behavior: Users on <flux:time-picker time-format="24-hour"> with (Hebrew page locale) experience an unhandled JavaScript error during normal interaction with the picker (focus → blur on the hour input, or keyboard navigation). The error reaches the browser's global handler and the picker stops responding.
Error thrown:
Error: Invalid time string: 16:27 לפנה״צ
(The exact prefix varies — 16:27, 21:19, 09:49, etc. — and the meridiem is either לפנה״צ (AM) or אחה״צ (PM), depending on the picker's selected hour.)
Why this is unexpected: The component is explicitly configured with time-format="24-hour". The documented contract is that no meridiem should be involved at all — neither displayed nor parsed — so an "Invalid time string" containing a day-period substring shouldn't be reachable. In practice on the affected browser it is reachable.
Where it surfaces: processTime() in UITimePickerTrigger reads this.meridiemInput?.value and passes the value to getTime() → convertTimeStringTo24HourFormat(). The vendor regex /^(\d{1,2}):(\d{2})(?:\s*(am|pm|AM|PM))?$/i rejects any non-ASCII meridiem and throws.
Impact: The error is unhandled at the runtime level — the action promise rejects, Sentry captures it under auto.browser.global_handlers.onerror, and the user is left with a non-functional time picker. In our production deployment this resulted in 6 recorded events from real users over ~2 weeks (likely undercount, since only those whose sessions still had Sentry connectivity made it through).
Configuration that triggers it: time-format="24-hour" on the component, page locale that produces a non-ASCII dayPeriod from Intl.DateTimeFormat (he, and likely others — ar, zh, etc., though we haven't observed those in production).
Code snippets to replicate the problem
Minimal Blade setup that exhibits the bug in production:
{{-- layouts/app.blade.php (or any layout) --}}
{{-- resources/views/livewire/time-picker-repro.blade.php --}}
// app/Livewire/TimePickerRepro.php
Open the page on Samsung Internet 29.0 / Android 10 (or any browser exhibiting the boot-time race). Focus the hour input, type/scroll any value, blur. The console throws Invalid time string: HH:MM .
Force-trigger in any browser (proves the regex throws on a locale day-period):
This bypasses the boot-time race and directly exercises the broken parser. Useful for verifying the fix in CI without needing the affected device:
convertTimeStringTo24HourFormat('16:27 לפנה״צ'); // throws
convertTimeStringTo24HourFormat('17:02 אחה״צ'); // throws
convertTimeStringTo24HourFormat('16:27 AM'); // ok
The regex's optional capture group only matches am|pm (case-insensitive ASCII). Any locale that produces a non-ASCII dayPeriod from Intl.DateTimeFormat(locale, { hour12: true }) — Hebrew, Arabic, Chinese, Japanese, Korean, etc. — will trigger this if it ever reaches the parser.
Screenshots/ screen recordings of the problem
Here's an honest block for that section — since the bug is on a device class we don't physically have, we can't produce a direct recording. Acknowledge that and substitute the evidence we do have:
Screenshots / screen recordings
We do not have a direct screen recording — the bug is reproducible only on Samsung Internet 29.0 / Android 10 with a Hebrew system locale, which we don't have physical access to. All affected users are in production.
Substituting the evidence we have:
Production console error (as captured by Sentry across 6 events):
How do you expect it to work?
With time-format="24-hour" explicitly set, the picker should treat the meridiem concept as completely off — neither rendered, nor read, nor parsed — regardless of or browser-specific timing of when picker.config.timeFormat becomes available.
Specifically:
No JavaScript errors should reach the global handler during any interaction with the picker, on any browser, with any page locale.
The picker should accept "HH:mm" input and emit "HH:mm" to wire:model, with no AM/PM logic involved at any point in the data path.
The fact that Intl.DateTimeFormat(locale, { hour12: true }) returns a non-ASCII dayPeriod for some locales should be irrelevant when time-format="24-hour" is configured. (Or, ideally, irrelevant in the 12-hour case too — the parser should accept locale day-periods or only operate on the internal 24-hour value — but that's a larger change.)
In other words, the behavior on Samsung Internet 29.0 with Hebrew locale should be the same as it is today on Chrome desktop with English locale: the picker works, no console errors, no Sentry events.
Smallest possible fix that achieves this: call this.use24HourFormat() lazily inside processTime() (or in the meridiem-read path) instead of relying on the boot-time decision in this.meridiemInput = null. Any browser timing race in boot() then stops mattering.
Please confirm (incomplete submissions will not be addressed)