Description
What is error 190?
Error 190 (Access Token Invalid) is the Graph API error returned when the access token sent with a request can't be used. It comes back as an OAuthException with "code": 190, usually with HTTP 401, and covers every way a token can stop working: it expired, the user removed the app, the session was invalidated by a password change or a security checkpoint, or the string isn't a valid token at all. Every Graph API call fails with it, including WhatsApp Cloud API sends, template syncs and media downloads, until a working token is supplied.
The error_subcode tells you which case you are in. Meta documents 463 (expired), 460 (password changed), 467 (invalid access token: expired, revoked or otherwise invalid), 458 (the user has not authorised the app), 459 and 464 (the user must log in to Facebook to clear a checkpoint or confirm the account) and 492 (invalid session). A 190 with no subcode often means a malformed token: truncated when copied, wrapped in quotes, or sent without the Bearer prefix. The message adds detail, as in “Error validating access token: Session has expired on…”.
Error 190 is about whether a token is alive, not what it may do. When a valid token lacks a permission such as whatsapp_business_messaging, or its system user hasn't been assigned the WABA, the Graph API returns permission errors (code 10, or codes from 200 to 299), and a new token without the right API permissions won't help. Lifetimes differ by token type: the temporary token on the WhatsApp page of the App Dashboard lasts 24 hours, user tokens expire (a long-lived access token lasts weeks, not forever), and a system user access token can be generated with no expiry at all.
Key takeaways
- Error 190 means the access token on the request can't be used: it has expired, been revoked, been invalidated or is malformed.
- It arrives as an
OAuthException, usually with HTTP 401, and theerror_subcodesays why. - Subcode 463 is an expired token, 460 a password change, 467 an invalid token and 458 an app the user hasn't authorised.
- Production WhatsApp sending should use a system user access token, not the 24-hour temporary token from the App Dashboard.
- A valid token that lacks a permission returns code 10 or 200–299 instead; regenerate tokens only for 190.
Mechanics
How does error 190 work?
step 1 — Detect it by code, not by status
Branch on
error.code === 190and itserror_subcodein every Graph API client, and mark it non-retryable: the same token will fail again.step 2 — Inspect the token
Call
GET /debug_token?input_token={TOKEN}with an app access token, or paste it into the access token debugger, to seeis_valid,expires_at,scopesand the WABAs ingranular_scopes.step 3 — Apply the fix for the subcode
463 or 467: issue a new token. 460: the user has to log in again. 458: send the user back through the login or Embedded Signup flow. No subcode: check the token string and the header format.
step 4 — Pause sending and alert
Stop the queue so messages aren't burned on failures, page the owner, and keep the queue intact for replay once a new token is in place.
step 5 — Move servers to a system user token
For server-to-server sending, generate a system user token with only the WhatsApp permissions you need, keep it in secrets management, and plan token rotation.
Caveats
Common mistakes with error 190
Shipping the temporary token
The token on the App Dashboard's WhatsApp page is for testing and lasts 24 hours. Production code that uses it fails the next day; use a system user token.
Retrying 190 like a transient error
Generic retry wrappers multiply failures and hide the real alert. Treat 190 as fatal for that token: pause, alert, replace.
Regenerating tokens for a permission error
If the error is code 10 or 200–299, the token is fine and lacks a scope or an asset. Fix permissions or WABA assignment; a fresh token with the same scopes fails the same way.
Tying production to a person's login
A developer's user token dies when they change their password, leave the company or remove the app. Server traffic belongs on a system user that no individual owns.
Logging tokens while debugging
Tokens pasted into logs, tickets and chat are credentials anyone can use. Log the debug_token result (validity, expiry, scopes), never the token itself.
Usage
Error 190 in code
{"error": {"message": "Error validating access token: Session has expired on Saturday, 17-Oct-26 14:00:00 PDT. The current time is Saturday, 17-Oct-26 15:12:09 PDT.","type": "OAuthException","code": 190,"error_subcode": 463,"fbtrace_id": "AqLr5Xk2Y8vN3pB"}}
Properties
Error 190: key facts and limits
- Code and type
- 190 · OAuthException
- HTTP status
- 401 Unauthorized
- Key subcodes
- 463 expired · 460 password changed · 467 invalid · 458 not authorised
- Temporary dashboard token
- Expires after 24 hours
- System user token
- Can be generated with no expiry (expires_at 0)
- Not this error
- Code 10 or 200–299: permission missing
- Retry?
- No: replace the token
Example
Example: A weekend outage in Pune
A Pune edtech start-up launches WhatsApp class reminders on a Friday using the temporary token copied from the App Dashboard. On Saturday afternoon every send fails with code: 190, error_subcode: 463: the token had lasted 24 hours. The retry logic hammers the API until 30,000 failed attempts sit in the logs. The fix is a system user in the business portfolio, assigned to the WABA, with a token carrying whatsapp_business_messaging and whatsapp_business_management, stored in a secrets manager, plus a rule that any 190 pauses the queue and pages the on-call developer.
Why it matters
Why does error 190 matter?
190 takes a whole integration down at once: every send, every template sync and every media download fails from the moment the token dies, often at a weekend because a temporary token was shipped to production. Recognising it by code and subcode, instead of retrying it like a network blip, lets you alert immediately, pause the send queue and swap in a valid token before messages pile up or are lost.
Notes
Best practices for error 190
- Check every token's
expires_atwith debug_token at deploy time, and alert well before expiry. - Grant system users only the WhatsApp permissions and WABAs they need.
- Store tokens in a secrets manager and reload them without a redeploy.
- If a 190 makes no sense, send Meta support the fbtrace_id from the error.
Questions
Error 190 (Access Token Invalid) FAQs
- What does Graph API error 190 mean?
- The access token on the request can't be used: it has expired, been revoked, been invalidated or is malformed. The error_subcode in the response tells you which.
- How do I fix “Error validating access token: Session has expired”?
- Issue a new token: this is subcode 463. For WhatsApp sending, replace temporary or user tokens with a system user access token so the expiry doesn't recur.
- How long does the WhatsApp temporary access token last?
- 24 hours. It is meant for testing from the App Dashboard; production integrations should use a system user access token instead.
- What is the difference between error 190 and error 200?
- Error 190 means the token itself is invalid. Codes 10 and 200–299 mean the token is valid but lacks a permission or access to the asset, so the fix is scopes or assignment, not a new token.