firebase deploy --only hosting blows up mid-run with HTTP Error: 400, HTTP Error: 401, Request had invalid authentication credentials, Failed to make request to https://firebasehosting.googleapis.com/..., or Site quota exceeded. The Hosting deploy pipeline is short, so failures cluster into four buckets: stale CLI, expired auth, a wrong public path in firebase.json, and Spark-plan quota.
Fastest fix (works for most cases): re-run with --debug to see the real error, then upgrade the CLI and re-authenticate:
npm install -g firebase-tools@latest
firebase login --reauth
firebase deploy --only hosting --debug
If that still fails, the --debug log tells you which bucket you are in. The rest of this article maps each error string to its root cause and exact fix.
Which bucket are you in?
Match the string in your --debug log to the cause:
| Error string in the log | Root cause | Jump to |
|---|---|---|
Unexpected error, Failed to parse host, Cannot read propert... | CLI too old | Cause 1 |
HTTP Error: 401, Request had invalid authentication credentials, have you run firebase login? | Expired / wrong-account auth | Cause 2 |
found 0 files in public, deploy completes but the live site is blank | public path wrong | Cause 3 |
Site quota exceeded, QUOTA_EXCEEDED, over its quota | Spark quota hit | Cause 4 |
Invalid hosting configuration, Specified "redirects" config is not valid | Bad rewrites/redirects syntax | Cause 5 |
Causes, ordered by hit rate
1. CLI is too old or mismatched with the project
The Firebase CLI changes its API protocol every few months. Old versions (especially below v13) throw vague errors like Unexpected error: ... or Failed to parse host for cases newer CLIs handle cleanly. As of June 2026 the current line is firebase-tools 15.x; anything two or more major versions behind is a real risk.
$ firebase --version
9.22.0 # too old — upgrade to the latest (15.x as of June 2026)
How to spot it: errors like Cannot read property 'X' of undefined or Unexpected token in JSON when you have not touched your config.
2. Auth token expired or you switched Google accounts
The CLI stores credentials at ~/.config/configstore/firebase-tools.json. When the token expires or your active Google account changes, you get HTTP Error: 401, Request had invalid authentication credentials or Failed to authenticate, have you run firebase login?.
How to spot it: firebase login:list shows an account that does not own this project, or shows nothing at all.
3. firebase.json public path does not match the build output
The public field names the directory that gets uploaded. Astro builds to dist/, Next.js static export to out/, Vite to dist/ — but many projects keep the firebase init default "public": "public" and upload an empty folder.
// firebase.json — typical config for an Astro static site
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [{ "source": "**", "destination": "/index.html" }]
}
}
How to spot it: the deploy log shows i hosting[project]: found 0 files in public — you uploaded nothing. The deploy “succeeds” but the live URL is blank or 404.
4. Spark plan quota exhausted
As of June 2026 the Spark (free) plan gives each project 10 GB of Hosting storage total and 10 GB of data transfer per month, with a per-file cap of 2 GB. The two limits fail differently:
- Storage past 10 GB: new deploys are blocked. You see
Site quota exceeded/QUOTA_EXCEEDED. Old releases keep counting against storage even after you ship new ones, so a long-lived project accumulates. - Transfer past 10 GB/month: your live sites are disabled until the next billing cycle (or until you upgrade to Blaze) — this hits visitors, not your deploy.
How to spot it: Firebase Console -> Hosting -> Usage tab — check the Storage and Data transfer gauges.
5. Syntax error in rewrites / redirects
Common manual mistakes: source and destination swapped, the ** glob written as *, or a redirect missing the required type (301/302). The CLI only validates these at deploy time, so the local config “looks fine.”
// Wrong: missing required type field
"redirects": [
{ "source": "/old", "destination": "/new" }
]
// Right
"redirects": [
{ "source": "/old", "destination": "/new", "type": 301 }
]
How to spot it: the log contains Invalid hosting configuration or Specified "redirects" config is not valid.
Shortest path to fix
Pull the full log first, then upgrade / re-auth / config / quota in that order.
Step 1: Re-run with --debug to get the full stack
The default output collapses the real error. Add --debug and save it:
firebase deploy --only hosting --debug 2>&1 | tee firebase-deploy.log
Search the log for [ERROR] or HTTP Error: — the root cause (PERMISSION_DENIED, INVALID_ARGUMENT, QUOTA_EXCEEDED, etc.) is usually right next to it. Use the table above to pick a cause.
Step 2: Upgrade the CLI and re-authenticate
# Upgrade globally
npm install -g firebase-tools@latest
firebase --version # expect 15.x (June 2026)
# Refresh the token in place — keeps your account, just re-mints the token
firebase login --reauth
# Confirm the active account owns the project
firebase login:list
firebase projects:list # confirm your project_id is in the list
If --reauth does not clear it, do a full firebase logout && firebase login. On a headless box add --no-localhost to paste a code instead of opening a browser.
Step 3: Verify firebase.json public matches your build output
# What was actually built
ls -la dist/ # or out/, build/, public/ — depends on the framework
# What firebase.json points at
grep '"public"' firebase.json
They must match. Common framework defaults:
| Framework | Build output dir |
|---|---|
| Astro (static) | dist |
| Next.js (static export) | out |
| Vite | dist |
| Create React App | build |
| Vue CLI / Vite (Vue) | dist |
| SvelteKit (static adapter) | build |
firebase deploy --only hosting --dry-run runs the upload steps without publishing, so you can confirm the file count before going live.
Step 4: Reproduce locally with the emulator
firebase emulators:start --only hosting
# Open http://localhost:5000 — matches production behavior
# rewrites / redirects errors surface here exactly like in deploy
Fix the config, confirm it in the emulator, then deploy.
Step 5: If quota is the issue
If Step 1’s log shows QUOTA_EXCEEDED or Site quota exceeded:
- Firebase Console -> Hosting -> Usage to see current Storage and Transfer numbers.
- Short-term (storage): delete old release versions (Hosting -> Release history -> pick an old release -> Delete) to free storage and unblock the next deploy.
- Transfer limit hit: there is no way to reset the monthly transfer counter on Spark; you either wait for the next billing cycle or upgrade.
- Long-term: upgrade to the Blaze pay-as-you-go plan. As of June 2026, beyond the free tier you pay $0.026/GB-month for storage and $0.15/GB for data transfer — for most small sites still a few cents a month. Set a Cloud Billing budget alert so Blaze cannot surprise you.
Step 6: Validate rewrites / redirects syntax
Cross-reference firebase.json against the Hosting config reference. Or validate locally against the published schema:
npx ajv-cli validate \
-s https://raw.githubusercontent.com/firebase/firebase-tools/master/schema/firebase-config.json \
-d firebase.json
How to confirm it’s fixed
firebase deploy --only hostingexits0and prints a non-zero file count, e.g.i hosting[project]: file upload completefollowed by+ Deploy complete!.- Open the Hosting URL from the deploy output (not a cached tab) in a private window and confirm the new content loads.
- Firebase Console -> Hosting -> Release history shows a fresh release with the current timestamp and the expected file count.
- If you fixed rewrites/redirects, hit a redirected path with
curl -I https://YOUR-SITE.web.app/oldand confirm the301/302andlocationheader.
Prevention
- Pin firebase-tools in
package.jsondevDependencies (e.g."firebase-tools": "15.20.0") so the whole team and CI run the same version. - In CI, prefer a service account key via
GOOGLE_APPLICATION_CREDENTIALSoverfirebase login:ci. TheFIREBASE_TOKEN/login:ciflow is deprecated and slated for removal in a future major version of firebase-tools. - Run
firebase hosting:channel:deploy previewon PRs so firebase.json bugs surface before merging to main. - Add a pre-deploy check like
firebase emulators:exec "echo ok" --only hostingso config errors fail locally. - Set a Cloud Billing / Firebase budget alert (works even on Spark) to email at 80% of your storage or transfer quota.
FAQ
Why did firebase deploy say “Deploy complete!” but my site is blank?
The public directory was empty or wrong — look for found 0 files in public in the log. Point public at your real build output (dist, out, or build) and redeploy. See Cause 3.
How do I fix HTTP Error: 401, Request had invalid authentication credentials?
Your token expired or you switched Google accounts. Run firebase login --reauth, then firebase login:list to confirm the active account owns the project. In CI, use a service account key, not an interactive login.
What CLI version should I be on?
The current firebase-tools line is 15.x as of June 2026. Run npm install -g firebase-tools@latest. Pin the exact version in package.json so CI matches local.
I hit “Site quota exceeded” — do I have to pay? Not necessarily. If it is storage, delete old releases (Hosting -> Release history) to drop back under 10 GB. If it is monthly transfer, you wait for the next billing cycle or upgrade to Blaze; Blaze overage is about $0.15/GB transfer, so small sites typically pay cents.
Does deploying delete my old version automatically? No. Old releases stay in Release history and keep counting toward the 10 GB storage cap. Prune them periodically or you will eventually hit the quota on a free project.
Can I validate firebase.json before deploying?
Yes — firebase deploy --only hosting --dry-run runs everything except publishing, and the emulator (firebase emulators:start --only hosting) reproduces rewrites/redirects errors locally.