Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIRESTORE (7.14.3) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array #3096

Closed
rodrigoehlers opened this issue May 21, 2020 · 15 comments

Comments

@rodrigoehlers
Copy link

rodrigoehlers commented May 21, 2020

Describe your environment

  • Operating System version: macOS Catalina Version 10.15.4
  • Browser version: None
  • Node.js version: 12.5.0
  • Firebase SDK version: 7.14.4 (implicitly through latest @firebase/testing)
  • Firebase Testing SDK version: 0.19.4
  • Firebase Product: firestore and testing
  • Jest version: 26.0.1

Describe the problem

Steps to reproduce:

Use the code below, then run tests with jest <path-to-your-file>. In my case <path-to-your-file> was ./spec/basic.spec.js.

It seems that firebase.assertFails(...) throws an error and never returns. Jest doesn't exit.

You'll receive the following logs:

(node:18117) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
 FAIL  spec/basic.spec.js
  Minimal test
    ✕ this tests throws an error and never returns (286 ms)

  ● Minimal test › this tests throws an error and never returns

    FIRESTORE (7.14.3) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array

      at fail (node_modules/@firebase/firestore/src/util/assert.ts:39:9)
      at hardAssert (node_modules/@firebase/firestore/src/util/assert.ts:53:5)
      at JsonProtoSerializer.fromBytes (node_modules/@firebase/firestore/src/remote/serializer.ts:250:7)
      at JsonProtoSerializer.fromWatchChange (node_modules/@firebase/firestore/src/remote/serializer.ts:431:32)
      at PersistentListenStream.onMessage (node_modules/@firebase/firestore/src/remote/persistent_stream.ts:568:41)
      at node_modules/@firebase/firestore/src/remote/persistent_stream.ts:448:21
      at node_modules/@firebase/firestore/src/remote/persistent_stream.ts:501:18
      at node_modules/@firebase/firestore/src/util/async_queue.ts:358:14

  console.error
    [2020-05-21T14:11:50.900Z]  @firebase/firestore: Firestore (7.14.3): FIRESTORE (7.14.3) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array

      at Logger.defaultLogHandler [as _logHandler] (node_modules/@firebase/logger/src/logger.ts:115:57)
      at Logger.error (node_modules/@firebase/logger/src/logger.ts:203:21)
      at logError (node_modules/@firebase/firestore/src/util/log.ts:45:20)
      at fail (node_modules/@firebase/firestore/src/util/assert.ts:34:3)
      at hardAssert (node_modules/@firebase/firestore/src/util/assert.ts:53:5)
      at JsonProtoSerializer.fromBytes (node_modules/@firebase/firestore/src/remote/serializer.ts:250:7)
      at JsonProtoSerializer.fromWatchChange (node_modules/@firebase/firestore/src/remote/serializer.ts:431:32)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.203 s
Ran all test suites matching /.\/spec\/basic.spec.js/i.
Jest did not exit one second after the test run has completed.

This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.

Relevant Code:

Use the following as firestore.rules:

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read: if false;
      allow write: if false;
    }
  }
}

Create a minimal test, reading from a collection:

const firebase = require('@firebase/testing');

describe('Minimal test', () => {
  const projectId = 'project-id';
  let db;
  let ref;

  beforeAll(() => {
    db = firebase.initializeTestApp({ projectId }).firestore();
    ref = db.collection('hello-world');
  });

  afterAll(() => Promise.all(firebase.apps().map((app) => app.delete())));

  test('this tests throws an error and never returns', async () => {
    await expect(await firebase.assertFails(ref.get()));
  });
});

What have I tried

Downgrading @firebase/testing to version ^0.15.0 fixed the issue.

When I tested on my real rules and tests however, it seems to have broken the test reports as setValue is not in const compressedTypes = ['mapValue', 'listValue', 'constraintValue'] in the repost .html function buildValueString(...) yet? This is only speculation! It could be that my rules are simply wrong.

The report .html therefore throws the following error a couple of times:

Found invalid expression-return type.

Someone with a similar issue posted on StackOverflow.

@dconeybe
Copy link
Contributor

Thank you for reporting this issue. I was able to reproduce and created a GitHub repository with my reproduction steps: https://github.com/dconeybe/FirebaseJsBug3096. I will look into this and update this bug with my findings.

thomastoye added a commit to hoepel-app/hoepel-app that referenced this issue May 22, 2020
@dconeybe
Copy link
Contributor

Just an update that I am still investigating. I have not found the root cause yet.

@gleno
Copy link

gleno commented May 26, 2020

Seeing this also. Any workarounds?

derat added a commit to derat/ascenso that referenced this issue May 29, 2020
I've lost track of which packages are getting upgraded here:
things under @babel, @firebase, @jest, yargs, much more.
This stuff is the worst.

I had to back off on some Jest upgrades since they caused
(bogus?) "Do not import `@jest/globals` outside of the Jest
test environment" errors in src/firebase/mock.ts that I
couldn't find any way to fix.

After doing this, downgrade @firebase/testing to 0.15.0,
since otherwise the Firestore rules tests fail due to this
bug reported 8 days ago:
firebase/firebase-js-sdk#3096

Sigh.
derat added a commit to derat/ascenso that referenced this issue May 29, 2020
I've lost track of which packages are getting upgraded here:
things under @babel, @firebase, @jest, yargs, much more.
This stuff is the worst.

I had to back off on some Jest upgrades since they caused
(bogus?) "Do not import `@jest/globals` outside of the Jest
test environment" errors in src/firebase/mock.ts that I
couldn't find any way to fix.

After doing this, downgrade @firebase/testing to 0.15.0,
since otherwise the Firestore rules tests fail due to this
bug reported 8 days ago:
firebase/firebase-js-sdk#3096

Sigh.
@rodrigoehlers
Copy link
Author

The issue seems to be resolved with firebase version @7.14.6 and @firebase/testing version @0.19.6. I just upgraded both, re-ran tests and all my tests passed without issues.

@thomastoye
Copy link

I'm still seeing this with

@mythyme
Copy link

mythyme commented May 30, 2020

I'm also seeing this, but am using firebase directly not firebase-testing

[email protected]
[email protected]
[email protected]
[email protected]

@moscoso
Copy link

moscoso commented May 31, 2020

I'm seeing this with [email protected] and "@angular/fire": "^5.4.2","firebase-tools": "^7.12.1",
in my angular project

@dconeybe
Copy link
Contributor

dconeybe commented Jun 1, 2020

Update: Although my investigation is still in progress, here is what I have so far. It looks like this behavior may be due to a "bug" in Jest. The problem surfaces in the follow code from serializer.ts:

value === undefined || value instanceof Uint8Array

The value object is an instance of Buffer, which is a subclass of Uint8Array; however, the value instanceof Uint8Array is mysteriously evaluating to false, causing the assertion failure.

My hypothesis is that the Jest testing framework is doing something wonky with "realms", an advanced feature that allows for different global memory spaces for different parts of a JavaScript program. This has come up as an issue with Jest before, and there is a potential workaround: jestjs/jest#7780.

@dconeybe
Copy link
Contributor

dconeybe commented Jun 2, 2020

It looks like the workaround documented in jestjs/jest#7780 fixes the problem. I've updated my reproduction app, https://github.com/dconeybe/FirebaseJsBug3096, with the workaround steps and a workaround branch to demonstrate it.

Since this issue does not appear to be a bug in the Firebase SDK, but rather a side effect of how Jest executes tests, I am going to close this ticket. Feel free to re-open, however, if you disagree and we can continue the discussion. If you think of it, please report back your success with this or other workarounds.

@dconeybe dconeybe closed this as completed Jun 2, 2020
@dconeybe dconeybe added the bug label Jun 2, 2020
@taronaeo
Copy link

taronaeo commented Jun 3, 2020

+1

Just came across this error with Jest as well and the workaround is perfect! Followed the workaround and all my tests worked perfectly without any problems.

For others having the same issue and referring to this, use @dconeybe's workaround and your tests should run without problems again.

@moscoso
Copy link

moscoso commented Jun 6, 2020

Okay, so I'm not sure if this fix applies to other people or just me. But when I was designing my application, I was using Ng/Rx to manage state. I had actions, reducers, and effects designed around Firebase Auth state. I would store user info when a user was authenticated, but ALSO and here's the crucial mistake, I was also storing the credential object that gets passed in after angularFire auth login functions. To be specific I am talking about this credential object: https://firebase.google.com/docs/reference/js/firebase.auth.AuthCredential

Now, it took me 6 hours, I tried all sorts of different package versions, but I finally realized the cause of this error. What happens is if I tried to make or store a copy of the credential object values, it would always lead to all kinds of Internal Firebase errors with INTERNAL ASSERTION FAILED to be only one of them. After removing any code related to reading or writing the values that came from the credential object, the error went away completely.

TLDR; It looks like Firebase has some security code that causes errors when interacting with credential objects. Remove that and the Internal Assertion Failed goes away

@taronaeo
Copy link

taronaeo commented Jun 7, 2020

Sorry to bring this up again but apparently this solution does not work once you convert your tests into Typescript.

I've tried converting the solution from Javascript into Typescript but it still displayed the error:

(node:2960) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 4)
  console.error
    [2020-06-07T03:58:48.724Z]  @firebase/firestore: Firestore (7.14.5): FIRESTORE (7.14.5) INTERNAL ASSERTION FAILED: value must be undefined or Uint8Array

      at Logger.defaultLogHandler [as _logHandler] (node_modules/@firebase/logger/src/logger.ts:115:57)
      at Logger.error (node_modules/@firebase/logger/src/logger.ts:203:21)
      at logError (node_modules/@firebase/firestore/src/util/log.ts:45:20)
      at fail (node_modules/@firebase/firestore/src/util/assert.ts:34:3)
      at hardAssert (node_modules/@firebase/firestore/src/util/assert.ts:53:5)
      at JsonProtoSerializer.fromBytes (node_modules/@firebase/firestore/src/remote/serializer.ts:250:7)
      at JsonProtoSerializer.fromWatchChange (node_modules/@firebase/firestore/src/remote/serializer.ts:431:32)

Is there something I'm missing? Because I'm pretty sure the solution provided above will work for Typescript but I'm not sure if we need to change some things up.

Edit: I've resolved this problem.

Solution

  1. Create a jest.config.js
  2. Paste in this code
module.exports = {
  testEnvironment: "./__test-utils__/custom-jest-environment.js",
}
  1. Run your tests, it should work already.

@wilhuff
Copy link
Contributor

wilhuff commented Jun 7, 2020

@moscoso There's no special code for causing failures related to credential objects. So far the issue we've seen here had to do with Jest breaking globals in such a way that a value in the form of a Uint8Array would not pass a value instanceof Uint8Array test. The resolution discussed so far has been a workaround specific to Jest.

In your first post you listed a number of dependencies and versions but did not include Jest. Was that the complete set of dependencies you're using? If so, you might be experiencing a different issue. If you could post a minimal reproduction along the lines of dconeybe's, we can help you figure out what's going on.

@moscoso
Copy link

moscoso commented Jun 14, 2020

@wilhuff my issue turned out to be completely separate from OP and not having to do with Jest... Maybe there is no special code for that, all I'm saying is that if you try to copy the credential object after a login method from AngularFire auth service, it will lead to INTERNAL ASSERTION FAILED.... I could re-create code if you really need me to, but it's exactly what I said. It's not longer an issue for me, removing the code that copies that credential object fixed it for me. Just letting people know if they stumble upon this thread because of the INTERNAL ASSERTION FAILED message

@firebase firebase locked and limited conversation to collaborators Jul 3, 2020
@jhuleatt
Copy link
Contributor

For those that need jest-environment-jsdom instead of jest-environment-node, I was able to get my tests working with a similar workaround:

  1. Add jest-environment-jsdom as a dev dependency in package.json
  2. Add custom-jest-environment.js containing the following:
'use strict';

/**
 * Correct Jest bug that prevents the Firestore tests from running. More info here:
 * https://github.com/firebase/firebase-js-sdk/issues/3096#issuecomment-637584185
 */

const BrowserEnvironment = require('jest-environment-jsdom');

class MyEnvironment extends BrowserEnvironment {
  constructor(config) {
    super(
      Object.assign({}, config, {
        globals: Object.assign({}, config.globals, {
          Uint32Array: Uint32Array,
          Uint8Array: Uint8Array,
          ArrayBuffer: ArrayBuffer
        })
      })
    );
  }

  async setup() {}

  async teardown() {}
}

module.exports = MyEnvironment;
  1. Add the new custom environment to jest.config.js:
testEnvironment: './test/custom-jest-environment.js'

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants