Service auth is not available
Operating System
Windows 11
Environment (if applicable)
Vercel Edge with Qwik
Firebase SDK Version
10.13.1-canary.16d62d4fa (or lower)
Firebase SDK Product(s)
Auth
Project Tooling
Qwik (1.8.0)
Detailed Problem Description
When I use getAuth() on the server inside a Qwik app, I get the Service Auth is not available error. The local testing environment has no problems and works as expected.
It is literally something that gets errored out in Qwik with getAuth().
Possibly related to #8355
While I'm not sure why the error is thrown, it is coming from here: https://github.com/firebase/firebase-js-sdk/blob/629919ea760e35b7d880a099edf7f42b5bcbae4b/packages/component/src/provider.ts#L130
J
Steps and code to reproduce issue
I made a Repo:
- Add your Firebase environment variables to
.envand to Vercel Edge environment variables.
PUBLIC_FIREBASE_CONFIG={"apiKey":....,"authDomain"...}
-
Deploy to Vercel Edge.
-
Sign in with Google.
-
Click the
aboutlink in navigation. -
See error thrown.
If have isolated the error to getAuth(). This app doesn't use initializeApp or initializeServerApp, but the error is the same in either case.
Here is failing code.
J
I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
Hi @jdgamble555,
This reported error is generally realted to an Auth Instance being used without an initialized App Instance. This doesn't seem related to #8355 as that had to do with a lack of support for features in fetch, which would come much later in the usage of Auth.
Are you certain that there's a default instance of App initialized within the context of that Request Handler? It might be worth adding a call to initializeApp before the getAuth call to double check.
@DellaBitta - I just made the test repo so that you can see clearly what the problem is. This equally happens when the server is initialized. I already have a repo for that.
J
I'm not familiar with Qwik or Vercel Edge or the architecture of your app but what I can do is tell you what causes that error in the Firebase SDK.
The error is usually caused when the entry point bundle that initializeApp comes from (firebase/app) doesn't match the version of the @firebase/auth bundle that getAuth was imported from. A couple of reasons this happens is (1) mismatched package versions - you have a newer @firebase/app but an older @firebase/auth - sometimes caused by incomplete npm upgrades - cleaning out node_modules and lockfiles and reinstalling usually fixes it, (2) your app does multiple builds - for example, one for server and one for client, with different module resolution configurations - for example, the server build process looks for CJS or the "main" or "exports.node" paths in the package.json, while the client build process looks for "browser" or "module" or "exports.browser/import". This would lead to each process importing a different bundle (CJS vs ESM) which aren't aware of each other, and if you try to share across them, the getAuth() from one won't recognize the app from another.
I took a quick glance and noticed your repo gets the "app" to use for getAuth() in 3 different places, by two different methods, you initializeApp/getApp in 2 places and initializeServerApp in the file that you say you're getting the error in. Do you not get the error from the other two files? Are they all compiled into one app? Or is the initializeServerApp only used in an isolated process on the server? If you use app instead of initializeServerApp there, do you have the same error?
https://github.com/search?q=repo%3Ajdgamble555%2Fqwik-firebase-todo%20getAuth&type=code
Also does this problem only occur when deployed to Vercel Edge? Does it happen locally? Is there any way to deploy it locally so we can reproduce and diagnose it? If not, the best I can suggest is to dig into Qwik or Vercel Edge and try to understand which environments your various bits of code are running in, what the module resolution config might be for each environment if there are multiple environments, and try to give us a breakdown of what's running where, and with what module resolution config. Unfortunately I'm not an expert in these tools and I'm afraid if this isn't reproducible locally, the error is likely to happen somewhere in this tooling pipeline, and can't be figured out without more understanding of the steps of this pipeline. If you can provide insight into it, that would be great.
Well I know a few things:
1.) I only have one package version, not even sure how you would have two package versions.
2.) Since I am running on the server, it clearly has a build for the server and for the client. I have deleted package-lock.json and node_modules and rebuilt. Same error.
3.) Everything works fine locally, in dev and in production builds.
4.) As far as I can tell, everything compiles with type: "module" everywhere, even in vercel edge plugin. There is unfortunately not a Vercel Serverless plugin, so no way to test this.
5.) The problem only persists when I call, not bundle, but call getAuth() on the server. It does not seem to matter what initialize method I use.
Given this information, any way to isolate the problem (at least get rid of what the causes aren't)?
Here is my test repository with a simpler version - https://github.com/jdgamble555/qwik-firebase-test
Thanks,
J
2.) Since I am running on the server, it clearly has a build for the server and for the client. 5.) The problem only persists when I call, not bundle, but call
getAuth()on the server.
It seems like you have two separate builds and two separate copies of the Firebase SDK code - not sure if I'm reading right, but one is in a bundle? for client? And the other is not bundled but called directly out of node_modules by the server?
The way that the Firebase SDK manages different services is a component registry. When you import from firebase/app or firebase/auth, there's some code that runs immediately on load (before you call any methods like initializeApp or getAuth) that registers that service to a component registry in local memory. If you have different runtimes (as you seem to with server and client), then you'll create two different registries in two different namespaces that don't know about each other.
I don't know Qwik so I'm not very sure what's going on, but it seems like the setup when you run it locally must have some kind of shared context vs when you deploy it, where some of the build is shared but some of the code is run in a separate runtime?
My only guess would be to either further separate or further share the code to prevent this from happening. For further separating it, if there's any way to isolate the runtimes of server and client and prevent them from sharing anything after the build? For further sharing it, if there's any way to ensure they are using the same context? Perhaps make firebase external for the client build instead of bundling it, so that both builds are calling code in node_modules?
If none of this helps, we can try to get up to speed on Qwik and Vercel Edge deployment to debug it ourselves but this may take some time, as we have to prioritize this among our tasks.
The way that the Firebase SDK manages different services is a component registry. When you import from firebase/app or firebase/auth, there's some code that runs immediately on load (before you call any methods like initializeApp or getAuth) that registers that service to a component registry in local memory.
So, even if not one function gets called on the server, just by running "import," there is immediate code that gets ran?
If that is the case, what makes it a new copy of Firebase? Is there a way to delete whatever copy of Firebase is in memory? Why wouldn't it just detect the existing version and not run again? This is confusing to me.
I have modified my code again so that it is impossible to run any firebase imported function on the server:
https://github.com/jdgamble555/qwik-firebase-test
I still get the error. I am technically importing on the server, but not running any functions unless it is in the browser.
A few things:
- This problem does not exists locally (dev or prod)
- This problem does not exists on other frameworks when I import something on the server
- This problem seems to only exist on Vercel Edge or Cloudflare with Firebase
J
@hsubox76 - This is not an import problem. I just refactored my entire code base to use dynamic imports everywhere, and the problem still exists. It is impossible to run any firebase code on the server, except in the server route. This is the only place there has ever been a problem, and it doesn't seem to be related to any client bundling problems.
https://github.com/jdgamble555/qwik-firebase-test
J
Hi @jdgamble555,
I was able to reproduce the problem. It appears that something in the build pipeline is aggressively tree shaking portions of the Firebase JS SDK when it packages it for the edge runtime. The "service" mentioned in the log file is that fact that Auth cannot properly register itself with the instance of FirebaseApp (or FirebaseServerApp). This is due to the hooks it would use to register itself with the instance of App are inexplicitly missing from the SDK implementation.
I'm not that familiar with Qwik and I'm not sure how to tune the build pipeline, or even if there are ways to tune it. Do you have any thoughts on how that might be done?
In the meantime it might be worth using the Firebase REST API to get around this problem.
https://github.com/QwikDev/qwik/issues/7052#issuecomment-2472666689
To solve the problem, the firebase import needs to happen in a different file. This file should export helpers that expose the desired firebase functionality. Then when you use these helpers in your Qwik code, they won't be tree shaken and the firebase side effects can run on first import.
@DellaBitta - Is this something that is possible?
Thanks!
J
Hi @jdgamble555,
Unless I'm mistaken, I think this change has to be done in the app and not the SDK. The engineer refers to the "firebase import" which is at the app level. I left a comment asking for clarification in the Qwik issue a few days ago, but I haven't had a response. I think the intention is to have your app import in only one location and funnel all firebase requests through that file.
Hopefully they will respond soon. However, I'm dynamically importing all firebase imports in my project on the server and client, and on the server it is already in one file.
J
@DellaBitta - I'm getting a little clarity from Qwik team (not a lot), but I'm still convinced this is a Firebase issue because it seems to work fine on the local machine (dev and preview --- which apparently uses treeshaking) with dynamic imports.
It just doesn't work in non-Node environments from what I can see.
J
Yes, I've been mointoring their thread as well, and that fact that it works locally is expected. The tooling for their hosted worker environments seems to be causing the problem, whereas building locally executes less agressive packaging tools designed for your more roboust local environment, and those tools don't cause a problem.
The only tree shaking done by the qwik optimizer plugin is for client builds 🤔
Can you give an example of necessary code that is tree shaken away?
The Firebase JS SDK leans on side effects to stand-up and/or register Components, cross SDK communication mechanisms, at the time of import of the various different Firebase packages. That is when App, or Auth, or Firestore, are imported, etc.
It seems that these side effects aren't being executed, and/or are being lost, or maybe isolated from each other when one SDK is imported in one file and another SDK is imported from a different file (at least that's what it sounds like given the response in the Qwik repo).
Going back to the specific error above, the App component should have been created via a side effect upon Firebase App import, but when a subsequent instance of Auth is created, and it attempts to register itself with the App Component, an error is thrown because the App component doesn't exist. It was either never stood up to begin with, or perhaps it exists within a different scope than the Auth import (just speculating).
If you really want to get into the weeds then you can see that _registerComponent is invoked inline upon import if you look into the dist sources of the various Firebase SDKs.
Hey @jdgamble555. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Just making a post hoping to get an update!
J
Hi @jdgamble555,
No update on our end, unfortunately. This still seems to be a packaging tooling issue, or a lack of support for sidefects.
As I mentioned above, the Firebase JS SDK requires that side effects are honored for it to operate correctly, and it appears that the side effects are not being executed by the environment your deploying to. Either that or the different components are being stood up in different scopes, and that, too is either an app configuration issue or an environment issue. I'm not sure what else that we can do at this time.
Hey @jdgamble555. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Since there haven't been any recent updates here, I am going to close this issue.
@jdgamble555 if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.