Open Bug 2000604 Opened 11 months ago Updated 11 days ago

bam.barrister.com - Blank page is displayed

Categories

(Web Compatibility :: Site Reports, defect, P2)

Desktop
Windows 10

Tracking

(Webcompat Priority:P3, Webcompat Score:1, firefox145 affected, firefox146 affected, firefox147 affected, firefox160 affected)

REOPENED
160 Branch
Webcompat Priority P3
Webcompat Score 1
Tracking Status
firefox145 --- affected
firefox146 --- affected
firefox147 --- affected
firefox160 --- affected

People

(Reporter: bfarkas, Assigned: ksenia)

References

()

Details

(4 keywords, Whiteboard: [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success])

User Story

platform:windows,mac,linux,android
impact:site-broken
configuration:general
affects:all
branch:release
diagnosis-team:javascript
user-impact-score:0
autowebcompat-repro-status:success
autowebcompat-repro-chrome-mask-fixed:false
autowebcompat-repro-channels:nightly,stable,esr
autowebcompat-repro-report-os:all
autowebcompat-diagnosis-status:success
autowebcompat-intervention-status:success

Attachments

(4 files, 1 external file, 2 obsolete files)

Environment:
Operating system: Windows 10
Firefox version: Firefox 145.0

Steps to reproduce:

  1. Access: https://bam.barrister.com/techportal/
  2. Observe the page

Expected Behavior:
The page is displayed accordingly

Actual Behavior:
Blank page is displayed

Notes:

  • Reproduces regardless of the status of ETP
  • Reproduces in firefox-nightly, and firefox-release
  • Does not reproduce in chrome

Created from https://github.com/webcompat/web-bugs/issues/188926

Since nightly and release are affected, beta will likely be affected too.
For more information, please visit BugBot documentation.

Severity: -- → S2
User Story: (updated)
Webcompat Priority: --- → P2
Webcompat Score: --- → 6
Priority: -- → P2

Console log:

ignoring https://www.gstatic.com/firebasejs/8.10.1/firebase-messaging.js on tab 2 frame 0 shims.js:30:19

Uncaught ReferenceError: _flutter is not defined
    <anonymous> https://bam.barrister.com/techportal/:68
techportal:68:5
    <anonymous> https://bam.barrister.com/techportal/:68

Empty string passed to getElementById(). index.html

unreachable code after return statement main.dart.js:88576:1

Null check operator used on a null value main.dart.js:51134:78

TypeError: Instance of 'minified:XM': type 'minified:XM' is not a subtype of type 'minified:B' main.dart.js:51134:78

<empty string> main.dart.js:51134:78

WEBGL_debug_renderer_info is deprecated in Firefox and will be removed. Please use RENDERER. 2 canvaskit.js:15:383

Empty string passed to getElementById(). 2 index.html

Webcompat Score: 6 → 5

An error is hidden from console (you can add a breakpoint to where "Null check operator used on a null value" string exists.)

TypeError: can't access property "getApps", self.firebase_core is undefined
    gapq https://bam.barrister.com/techportal/main.dart.js:79015
    c_H https://bam.barrister.com/techportal/main.dart.js:46101
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    q https://bam.barrister.com/techportal/main.dart.js:5231
    c_H https://bam.barrister.com/techportal/main.dart.js:46139
    $0 https://bam.barrister.com/techportal/main.dart.js:196261
    0 https://bam.barrister.com/techportal/main.dart.js:70503
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    $1 https://bam.barrister.com/techportal/main.dart.js:64076
    KT https://bam.barrister.com/techportal/main.dart.js:65420
    $0 https://bam.barrister.com/techportal/main.dart.js:64584
    I_ https://bam.barrister.com/techportal/main.dart.js:5410
    vs https://bam.barrister.com/techportal/main.dart.js:64494
    $0 https://bam.barrister.com/techportal/main.dart.js:64547
    cJY https://bam.barrister.com/techportal/main.dart.js:5442
    cKv https://bam.barrister.com/techportal/main.dart.js:5444
    $1 https://bam.barrister.com/techportal/main.dart.js:64021
    cEX https://bam.barrister.com/techportal/main.dart.js:5214
    <anonymous> https://bam.barrister.com/techportal/main.dart.js:210449
    c https://bam.barrister.com/techportal/main.dart.js:24
    cjf https://bam.barrister.com/techportal/main.dart.js:5449
    bYo https://bam.barrister.com/techportal/main.dart.js:5555
    tl https://bam.barrister.com/techportal/main.dart.js:65428
    ad_ https://bam.barrister.com/techportal/main.dart.js:64509
    mR https://bam.barrister.com/techportal/main.dart.js:64507
    dn https://bam.barrister.com/techportal/main.dart.js:64414
    $1 https://bam.barrister.com/techportal/main.dart.js:69650
    promise callback*fA https://bam.barrister.com/techportal/main.dart.js:7968
    bXi https://bam.barrister.com/techportal/main.dart.js:489
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    q https://bam.barrister.com/techportal/main.dart.js:5231
    bXi https://bam.barrister.com/techportal/main.dart.js:494
    bXj https://bam.barrister.com/techportal/main.dart.js:460
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    q https://bam.barrister.com/techportal/main.dart.js:5231
    bXj https://bam.barrister.com/techportal/main.dart.js:481
    aEG https://bam.barrister.com/techportal/main.dart.js:442
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    q https://bam.barrister.com/techportal/main.dart.js:5231
    aEG https://bam.barrister.com/techportal/main.dart.js:451
    0 https://bam.barrister.com/techportal/main.dart.js:56487
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    q https://bam.barrister.com/techportal/main.dart.js:5231
    $0 https://bam.barrister.com/techportal/main.dart.js:56501
    lR https://bam.barrister.com/techportal/main.dart.js:56294
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    q https://bam.barrister.com/techportal/main.dart.js:5231
    lR https://bam.barrister.com/techportal/main.dart.js:56298
    0 https://bam.barrister.com/techportal/main.dart.js:57866
    s https://bam.barrister.com/techportal/main.dart.js:5245
    $2 https://bam.barrister.com/techportal/main.dart.js:64082
    q https://bam.barrister.com/techportal/main.dart.js:5231

There's this code in https://bam.barrister.com/techportal/main.dart.js:

      bpV(a, b) {
        var s = 0,
        r = A.r(t.H),
        q,
        p,
        o,
        n,
        m,
        l,
        k,
        j,
        i,
        h,
        g
        var $async$TP = A.m(
          function (c, d) {
            if (c === 1) return A.o(d, r)
            while (true) switch (s) {
              case 0:
                h = self
                g = h.document.createElement('script')
                g.type = 'text/javascript'
                g.crossOrigin = 'anonymous'
                q = 'flutterfire-' + b
                if (h.window.trustedTypes != null) {
                  h.console.debug('TrustedTypes available. Creating policy: ' + A.l(q))
                  try {
                    k = h.window.trustedTypes
                    j = A.cD(new A.aRv(a))
                    p = k.createPolicy(q, {
                      createScript: A.aac(new A.aRw()),
                      createScriptURL: j
                    })
                    o = p.createScriptURL(a)
                    n = A.ccw(o, 'toString', null, t.X)
                    m = p.createScript(
                      '            window.ff_trigger_' + b + ' = async (callback) => {\n              console.debug("Initializing Firebase ' + b + '");\n              callback(await import("' + A.l(n) + '"));\n            };\n          ',
                      null
                    )
                    g.text = m
                    h.document.head.appendChild(g)
                  } catch (f) {
                    l = A.a3(f)
                    h = J.cd(l)
                    throw A.h(new A.apf(h))
                  }
                } else {
                  g.text = '      window.ff_trigger_' + b + ' = async (callback) => {\n        console.debug("Initializing Firebase ' + b + '");\n        callback(await import("' + a + '"));\n      };\n    '
                  h.document.head.appendChild(g)
                }
                k = new A.aC($.aJ, t.LR)
                A.ccw(
                  t.lZ.a(h),
                  'ff_trigger_' + b,
                  A.cD(new A.aRx(b, new A.b8(k, t.zh))),
                  t.X
                )
                s = 2
                return A.j(k, $async$TP)
              case 2:
                return A.p(null, r)
            }
          }
        )
        return A.q($async$TP, r)
      },

Somehow this function is not being called in Firefox at all. There's trustedTypes check but that doesn't matter as the else branch is not being called either.

This function is supposed to import the latest firebase libraries and make firebase_core and few others available globally.

From the same script:

      c_H() {
        var s = 0,
        r = A.r(t.H),
        q = 1,
        p = [],
        o,
        n,
        m,
        l,
        k,
        j,
        i,
        h,
        g,
        f
        var $async$c_H = A.m(
          function (a, b) {
            if (a === 1) {
              p.push(b)
              s = q
            }
            while (true) switch (s) {
              case 0:
                if ($.aK == null) A.a2t()
                $.aK.toString
                q = 3
                n = $.f6
                n = (n == null ? $.f6 = $.kX() : n).gapq()
                m = A.ab(n).i('a9<1,hB>')
                s = A.H(new A.a9(n, A.cO4(), m), !1, m.i('a0.E')).length === 0 ? 6 : 7
                break
              case 6:
                s = 8
                return A.j(A.aRF(B.aef), $async$c_H)
              case 8:
              case 7:
                q = 1
                s = 5
                break
              case 3:
                q = 2
                f = p.pop()
                o = A.a3(f)
                A.hw(o)
                s = 5
                break
              case 2:
                s = 1
                break
              case 5:
                if ($.aK == null) A.a2t()
                n = $.aK
                n.toString
                m = $.cn()
                k = t.e8
                if (k.a(m.ghp().b.h(0, 0)) == null) A.am(
                  A.a8(
                    'The app requested a view, but the platform did not provide one.\nThis is likely because the app called `runApp` to render its root widget, which expects the platform to provide a default view to render into (the "implicit" view).\nHowever, the platform likely has multi-view mode enabled, which does not create this default "implicit" view.\nTry using `runWidget` instead of `runApp` to start your app.\n`runWidget` allows you to provide a `View` widget, without requiring a default view.\nSee: https://flutter.dev/to/web-multiview-runwidget'
                  )
                )
                j = k.a(m.ghp().b.h(0, 0))
                j.toString
                i = n.gVb()
                h = n.cy$
                if (h === $) {
                  m = k.a(m.ghp().b.h(0, 0))
                  m.toString
                  g = new A.az5(B.a4, m, null, A.aG(t.T))
                  g.b0()
                  g.aKV(null, null, m)
                  n.cy$ !== $ &&
                  A.ak()
                  n.cy$ = g
                  h = g
                }
                n.aBd(new A.a2i(j, B.b12, i, h, null))
                n.aaj()
                return A.p(null, r)
              case 1:
                return A.o(p.at( - 1), r)
            }
          }
        )
        return A.q($async$c_H, r)
      },

Case 6 should lead to install the script, but somehow Firefox and Chrome goes different routes in this function.

Chrome: 0, 6, 8, 5
Firefox: 0, 3, 5

Needs to investigate why.

Again in the same script:

        gapq() {
            var s, r, q, p, o, n, m, l = "of undefined"
            try {
                o = self.firebase_core.getApps()
                o = B.b.iD(o, t.B)
                n = o.$ti.i("a9<a6.E,pL>")
                n = A.H(new A.a9(o,A.cL0(),n), !0, n.i("a0.E"))
                o = A.ab(n).i("a9<1,mJ>")
                o = A.H(new A.a9(n,A.cO5(),o), !1, o.i("a0.E"))
                return o
            } catch (m) {
                s = A.a3(m)
                r = A.al(m)
                q = J.cd(s)
                p = J.cd(r)
                if (J.rA(q, l) || J.rA(p, l))
                    return A.b([], t.Nb)
                else
                    throw m
            }
        },

From the case 0 in comment #6. self.firebase_core.getApps() fail at this point on both browsers as the library is not loaded yet. The problem is that the catch clause tries to sniff on the error message, specifically whether it includes "of undefined" in the error .stack. But:

  1. The message from SpiderMonkey does not includes "of undefined".
    • V8: TypeError: Cannot read properties of undefined (reading 'getApps')
    • SM: can't access property "getApps", self.firebase_core is undefined
  2. Even if it does, .stack property does not include the error message on SM but only on V8.

Thus passing this to JS.

User Story: (updated)
Whiteboard: [webcompat-source:web-bugs] → [webcompat-source:web-bugs][autowebcompat:processed]
User Story: (updated)
Whiteboard: [webcompat-source:web-bugs][autowebcompat:processed] → [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:diagnose]

https://bam.barrister.com/techportal/ renders a completely blank grey page in Firefox: the Flutter app's startup fails, the Firebase JS libraries are never loaded (self.firebase_core stays undefined) and no UI is ever painted. Chrome loads the same URL and displays the Barrister "Technician Portal" sign-in screen with BAS Code/Password fields and a Sign in button.

Whiteboard: [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:diagnose] → [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:diagnosis-in-progress]

Root cause analysis generated by autowebcompat bot:

The site is a Flutter web app using FlutterFire. At startup the firebase_core_web plugin's FirebaseCoreWeb.apps getter runs before the Firebase JS SDK has been injected, so self.firebase_core.getApps() throws a TypeError. The plugin treats that as the expected "SDK not loaded yet" state, but detects it by string-matching the browser's TypeError text and its Error.prototype.stack against the hard-coded substring "of undefined" (dart2js main.dart.js line 81702: try { self.firebase_core.getApps() } catch (m) { if (String(unwrapException(m)).contains("of undefined") || String(getTraceFromException(m)).contains("of undefined")) return []; else throw m; }). V8 says "Cannot read properties of undefined (reading 'getApps')" and repeats that message as the first line of .stack, so the guard matches, apps returns empty, plugin registration completes, Firebase.initializeApp() runs and injects gstatic firebasejs 11.9.1, and the portal renders. SpiderMonkey says "can't access property getApps, self.firebase_core is undefined" and its .stack contains only frames with no message line, so neither string contains "of undefined"; the TypeError is rethrown out of FlutterFire plugin registration, Firebase.initializeApp() is never reached, the Firebase JS SDK is never injected, and the Flutter app dies during startup before painting a frame, leaving a blank grey page. Error message wording is implementation-defined and Error.prototype.stack is not specified at all; ECMA-262 only requires that the property access throw a TypeError (https://tc39.es/ecma262/#sec-requireobjectcoercible, https://tc39.es/ecma262/#sec-error.prototype.message, https://github.com/tc39/proposal-error-stacks).

Evidence:

Network: Chrome requests gstatic firebasejs 11.9.1 firebase-app.js/-firestore.js/-messaging.js; Firefox requests none of them. Both load the legacy 8.10.1 compat scripts from index.html and canvaskit.js/.wasm with 200. DOM: Chrome has three injected inline scripts defining window.ff_trigger_firebase_core/firestore/messaging; in Firefox they are absent and self has no firebase*/ff_trigger* keys. typeof self.firebase_core is "object" in Chrome, "undefined" in Firefox. Puppeteer instrumentation wrapping trustedTypes.createPolicy and HTMLScriptElement.prototype.text: Chrome logs "TrustedTypes available. Creating policy: flutterfire-firebase_core" (and firestore/messaging) with createScriptURL/createScript/script.text all succeeding; Firefox logs only the unrelated flutter-engine canvaskit policy, so injectSrcScript is never reached. Trusted Types is not the cause: running the same createPolicy/createScriptURL/createScript/script.text sequence by hand succeeds in both browsers. Installing a logging accessor on window.firebase_core isolated the divergence: both browsers read it first at main.dart.js:81702 (the apps getter, inside its try); Chrome then reads again at main.dart.js:81690 inside QF (initializeCore) and injects the SDK, while Firefox instead prints "Null check operator used on a null value", then "TypeError: Instance of minified:a_3 is not a subtype of minified:E" from lX (Firebase.app) at main.dart.js:81758 - the exception escaped the apps getter. Live check in both browsers of self.nope_xyz.getApps(): Firefox message "can't access property getApps, self.nope_xyz is undefined", stack has no message line, includes("of undefined") false for both message and stack; Chrome message "Cannot read properties of undefined (reading 'getApps')", stack starts with that message, both true. Reduced testcase at /app/diagnosis/testcase=_h36g51o.html reimplements only that guard: Chrome shows RESULT PASS (guard matched, recovered with []), Firefox shows RESULT FAIL (guard did not match, error rethrown), with both "of undefined" checks printed false.

User Story: (updated)
Whiteboard: [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:diagnosis-in-progress] → [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success]

Standardizing the error text isn't going to be easy. It seems like we could try an intervention here.

Assignee: nobody → kberezina
Status: NEW → ASSIGNED
Attachment #9651370 - Attachment is obsolete: true
Attachment #9651388 - Attachment is obsolete: true
Whiteboard: [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success] → [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:intervention]
Whiteboard: [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:intervention] → [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:intervention-in-progress]

The site's Flutter app (FlutterFire firebase_core_web) calls self.firebase_core.getApps() before the Firebase JS SDK is loaded. It treats the resulting TypeError as "SDK not loaded yet" only when the error string or its stack contains "of undefined", which is V8's wording. In SpiderMonkey the error is rethrown, Firebase is never initialized, and the page stays blank.

This adds a content script for https://bam.barrister.com/techportal/* that wraps the Error.prototype.stack getter. For TypeErrors whose message ends in "is undefined", it puts a V8-like "TypeError: Cannot read properties of undefined (...)" line in front of the stack.

User Story: (updated)
Whiteboard: [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success][autowebcompat:intervention-in-progress] → [webcompat-source:web-bugs][autowebcompat:processed][autowebcompat:repro-success]
Attachment #9665566 - Attachment description: Bug 2000604 - Add webcompat intervention for bam.barrister.com → Bug 2000604 - Add webcompat intervention for bam.barrister.com; r?ksenia
Status: ASSIGNED → RESOLVED
Closed: 12 days ago
Resolution: --- → FIXED
Target Milestone: --- → 160 Branch

Oops, I forgot to mark this as leave-open for tracking.

Status: RESOLVED → REOPENED
User Story: (updated)
Resolution: FIXED → ---
User Story: (updated)
Webcompat Priority: P2 → P3
Webcompat Score: 5 → 1
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: