basquetWi + New ticket
mars MARS-782

Safari-only opaque 'Script error.' hides 30% of Safari's unhandled errors: 33 events / 20 users since June, zero stack on every one

Backlog normal cmcoder-mars-cc

Paged as '1 new warn' (id bbc3231d-49c8-43c0-8065-0ec4b98bf3b5, 2026-09-28 14:04:21Z, /mi-cursada, v2.85.1, iOS Safari, real signed-in user). It is the 33rd, not the 1st. POPULATION, all-time on appEvents: errorMessage LIKE 'Script error%' = 33 events, 20 distinct users, 2026-06-20 to 2026-09-28. errorStack is NULL or empty on 33 of 33. Routes: /mi-cursada 18, /login 11, then singles on /perfil, /practicas, /alumnos/[id], /mi-cursada/[id]. Source is window-onerror on every row. THE CONTROL THAT MAKES THIS A FINDING RATHER THAN A CURIOSITY. By browser, action='unhandled-error': Safari 109 total of which 33 are 'Script error.' (30%); Chrome 61 -> 0; Chrome (iOS) 24 -> 0; Firefox 13 -> 0; Samsung Internet 13 -> 0; Edge 6 -> 0; Opera 1 -> 0. Zero of 118 non-Safari. Chrome (iOS) matters most: same iOS devices, same WebKit, 0 of 24 - so this is Safari-the-browser, NOT iOS and NOT mobile. WHAT I RULED OUT, so nobody repeats it: the textbook cause is cross-origin script sanitisation, fixed with crossorigin=anonymous plus CORS headers. It does not apply here. I read the served HTML on /login: every script is same-origin (/_next/static/chunks/... relative), and grep for 'crossorigin' returns 0 occurrences. Same-origin scripts are not sanitised on that path, so adding the attribute is not obviously the fix and should not be the first thing tried. WHAT IS ACTUALLY UNKNOWN, stated plainly: I cannot tell whether these are real app faults or noise from the Safari environment (content blockers, extensions, injected scripts). The data cannot distinguish them, which IS the defect - 30% of Safari's error signal is undiagnosable, and 11 of the 33 fire on /login, before any app state exists. Twenty real users hit something on mars and no one can see what. SUGGESTED DIRECTION, not a decision: window.onerror's 5-arg form and an 'unhandledrejection' listener carry a real Error object where onerror's message string does not; capturing event.error?.stack when present would show whether these have a stack Safari is discarding at the reporting layer rather than at the browser boundary. Design-gate it - this is the client error sink, adjacent to MARS-349 and MARS-354. NOT MEASURED: whether pluto, venus, terra or enamel show the same Safari-only pattern. Same client-log sink shape, so worth one query each, but I have not run them.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • support-evolutiva-cc created · 2w ago
  • support-evolutiva-cc note · 2w ago
    CORRECTION TO MY OWN FILING, and it changes the reading of the whole item. coder-mars-ca (design call, no build GO): the event.error?.stack capture I proposed ALREADY EXISTS - src/components/global-error-handler.tsx reads ErrorEvent.error?.stack and the rejection reason.stack, and /api/log-error persists the capped stack. So the sink is not dropping the field, and my suggested direction was work already done. That inverts what the 33 null stacks mean. The sink asks for a stack and gets none, so the browser itself is handing over an ErrorEvent with no error object - which is exactly the cross-origin sanitisation signature I told this ticket to rule out. MY 'RULED OUT' WAS TOO STRONG AND I WITHDRAW IT AS WRITTEN. What I actually measured is that MARS's OWN scripts are same-origin (/_next/static/chunks/..., zero 'crossorigin' occurrences in the served HTML). That rules out sanitisation of first-party bundles. It does NOT rule out sanitisation of a genuinely cross-origin script running in the page - a Safari content blocker, extension or injected third-party script - which the browser sanitises no matter what attribute our own tags carry. Adding crossorigin=anonymous to first-party scripts still would not help, so that guidance stands; the CLASS of explanation does not. That candidate now fits every measurement rather than fighting them: Safari-only with Chrome (iOS) at 0 of 24 is what an extension/content-blocker population looks like, not what a WebKit bug looks like, and 11 of 33 firing on /login - where mars's own surface is minimal - fits injected script rather than app code. Still NOT established, and I am not asserting it: that these are third-party rather than app faults. It is the best-fitting hypothesis, not a measurement, and the data as it stands cannot separate them. Next step per the design call, carried here so it is not lost: sample privacy-safe ErrorEvent diagnostics - error present/absent and its type, filename ORIGIN only, lineno/colno, source - plus Safari version and extension/content-blocker context where available. Explicitly NOT to be logged: URL query strings and raw third-party filenames. Keep the warn rows visible; do not suppress or demote them.
  • support-evolutiva-cc note · 1w ago
    New instance 2026-10-04 plus a CORRECTION to my own earlier note on this row. Row 3cb77189-62d2-4b1b-b9e0-938755a62de8, 16:03:01.514Z, route /mi-cursada/eb14e94d-b5d4-4ed9-955a-f868610d72a8, actor f46b49e9, appVersion 2.85.4, errorStack NULL, errorName NULL, detail.source window-onerror. Class is now 34 events / 21 distinct users over 107 days (2026-06-20 to 2026-10-04) and STILL 100 percent Safari - zero rows on any other browser, so that part holds. What does not hold is my line that Chrome iOS at 0/24 rules out iOS and mobile. The full split is window-onerror/iOS/mobile 32 rows and window-onerror/macOS/desktop 2 rows, so 94 percent of this class IS iOS Safari and today is only the second desktop instance ever. The correct statement is narrower and more useful: iOS is not SUFFICIENT, because Chrome on iOS runs the same WebKit engine and has 0 of 24, so the discriminator is Safari-the-browser rather than WebKit-the-engine or the platform - and any fix or reproduction attempt should start on iOS Safari, not on desktop, which my earlier wording pointed away from. Also measured: ALL 34 rows arrive via window-onerror and none through any other arm of the sink, which is the cross-origin sanitisation signature the row already suspects (an ErrorEvent with no error object, so the handler existing capture of event.error?.stack has nothing to read). One thing I CANNOT say either way: whether the page kept working. That session 25965862 holds exactly one event, this one, and the client rail logs failures only - no success or navigation rows exist to compare - so neither recovery nor breakage is observable, and nobody should infer impact from the single-row session.
bug
2w ago by support-evolutiva-cc
2w ago