Short answer
FCM could not process the request in time (503) or hit an unknown error (500). Check the FCM status dashboard for a disruption, then retry the same request with exponential backoff and random jitter, honoring any Retry-After header. Do not retry 400, 401, 403 or 404 errors, and stop retrying a message once it is no longer timely. If 500s persist, contact Firebase support.
Rather not fix it yourself? App Fix Ticket starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.
What is behind the error, and the fix
01
FCM is overloaded or has a disruption
“The server couldn't process the request in time.” Firebase, FCM ErrorCode (UNAVAILABLE)
UNAVAILABLE means FCM did not answer in time. Look at the FCM status dashboard at status.firebase.google.com before you change code. If there is an ongoing disruption, queue the messages and resend them with backoff once it clears.
02
Retrying at once, or all messages together
“Honor the Retry-After header if it is included in the response from the FCM Connection Server.” Firebase, FCM ErrorCode (UNAVAILABLE)
An instant retry, or a loop that resends every failed message at the same moment, adds load right when FCM is short of it. Wait before the first retry, double the wait each time, and add a random amount per message. If you call the HTTP v1 API directly, read the Retry-After header and wait at least that long.
import { initializeApp } from 'firebase-admin/app'; import { getMessaging } from 'firebase-admin/messaging'; initializeApp(); const RETRYABLE = ['messaging/server-unavailable', 'messaging/internal-error']; async function sendWithRetry(message, attempt = 0) { try { return await getMessaging().send(message); } catch (err) { if (!RETRYABLE.includes(err.code) || attempt >= 5) throw err; const delay = 10_000 * 2 ** attempt + Math.random() * 1_000; await new Promise((r) => setTimeout(r, delay)); return sendWithRetry(message, attempt + 1); } }03
Retrying errors that will never succeed
“For 400, 401, 403, 404 errors: abort, and do not retry.” Firebase, Scale up with FCM (Handling retries)
A retry loop that treats every failure as temporary keeps resending bad tokens, bad payloads and auth errors. Those requests add traffic and never go through. Retry only 500 and 503 errors with backoff, and 429 after the Retry-After wait; drop or fix the rest.
04
An INTERNAL (500) error that keeps coming back
“If the error persists, please contact Firebase support.” Firebase, FCM ErrorCode (INTERNAL)
A 500 is an unknown error on FCM’s side. Retry it the same way as a 503. If it keeps failing for the same request after backoff and the status dashboard is clear, collect the request and the full error response and send them to Firebase support.
Checked against the vendor’s docs on : Firebase docs: FCM HTTP v1 ErrorCode; Firebase docs: FCM error codes (Admin SDK); Firebase docs: Scale up with FCM.
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
“Very responsive, attentive to fixing bugs, and completed the project as needed! Thank you!”
Related: FCM QUOTA_EXCEEDED · FCM THIRD_PARTY_AUTH_ERROR · FCM registration token not registered · FCM invalid registration token