Meta CAPI Error Codes: Complete Troubleshooting Guide
How Meta CAPI Reports Errors
The Meta Conversions API is deliberately quiet: it returns minimal data to conserve bandwidth. A valid event payload earns a 2xx HTTP response and no ceremony. An invalid one comes back as a 4xx with a compact error object that follows the general Graph API shape:
{
"error": {
"message": "Message describing the error",
"type": "OAuthException",
"code": 190,
"error_subcode": 460,
"error_user_msg": "A message",
"fbtrace_id": "EJplcsCHuLu"
}
}Read it in this order: code picks the failure family, error_subcode narrows it, error_user_msg often contains a human-readable instruction, and fbtrace_id is the identifier Meta support uses to find the request in their logs. If you run a tracker, its outbound postback log shows you this JSON for every failed S2S call - that is your first reading point, not the ad account.
One more subtlety: Meta documents that batch behavior here differs from what you might expect. When any event in a batch is invalid, the request returns an error, but valid events carrying an event_id are still accepted; when you fix the broken records and resend the whole batch, already-stored events are dropped as duplicates instead of counting twice. A failed batch response is therefore not a reason to panic-rebuild your queue - it is a reason to fix the named events and resend. One exception exists: the 7-day ingestion limit rejects the entire request, valid events included, as the section below explains.
The Meta CAPI Error Codes You Will Actually See
Meta maintains a long error reference for the Marketing API; for conversion delivery, a short subset does nearly all the damage:
| Code | Meaning |
|---|---|
| 100 | Invalid parameter - a field is missing, wrongly typed, or malformed |
| 190 | Invalid OAuth 2.0 access token |
| 102 | Session key invalid or no longer valid |
| 10 | Application does not have permission for this action |
| 200 | Permission error - the token works but lacks the permission for this specific action or asset |
| 4 | Application request limit reached |
| 17 | User request limit reached |
| 1 | Unknown error - possibly a temporary issue on Meta's side |
Two codes deserve their own articles rather than table rows. Error 2804003 is the 7-day ingestion limit - Meta rejects an entire request when any event_time is older than 7 days - and it has a dedicated guide on why Meta rejects events older than 7 days. Code 368 means the account or action got temporarily blocked for policy violations; no payload fix applies there, the resolution runs through account quality, not through your integration.
Fixing Error 100: Invalid Parameter
Error 100 is the generic "invalid parameter" response, and it fires on structural payload problems: a missing required field (event_name, event_time, action_source), an invalid enum value, a timestamp in milliseconds instead of Unix seconds, or a malformed currency or value field. Note one trap: unhashed user data usually does NOT return error 100 - Meta accepts the event and ignores the malformed field, surfacing a warning instead and quietly degrading your Event Match Quality. That is why hashing discipline still matters, but it lives in the validation section, not in the error log; the mechanics are in Event Match Quality.
The dangerous variant is 100 with error_subcode: 33. Per Meta's reference, it means an unsupported post request - your access token is not attached to the ad account that owns the object you are writing to, as a system user with appropriate permissions. The official recovery is administrative: the access token must belong to a system user with appropriate permissions on the asset - in Business Settings that means Business Settings -> System Users -> your user -> Add Assets, assigning the pixel or dataset (and the ad account) with full control, then retrying. No amount of payload tweaking fixes a subcode 33 - it is an access structure problem.
Other 100 subcodes exist for deprecated targeting categories and unsupported task combinations; the message and subcode pair always names the actual parameter problem. Trust the pair, fix the named field, and only then resend.
Fixing 190 and 102: Token and Session Errors
Code 190 means the OAuth access token is invalid or expired; code 102 means the session is no longer valid; code 200 means the token works but lacks the permission for the specific action or asset - the classic case when a shared pixel belongs to a different business than the token. The user-facing symptom is identical - events that delivered yesterday start failing today, often after a token rotation, a person leaving the team, or a business reorganization in Business Manager.
The recovery path: generate a fresh long-lived access token for a system user, and verify that system user has a role on the ad account that owns the pixel. Where your tokens live matters: a token pasted into a tracker field, a tag manager variable, or a cron script dies quietly when the underlying credential expires. The full provisioning flow is in the Meta pixel ID and access token guide. Authentication subcodes (463, 467, 460) narrow the cause - expired, revoked, or password changed - but the fix converges on the same fresh token.
Fixing Throttling: Codes 4 and 17
Code 4 is the application-level request limit; code 17 is the user-level limit. Code 1 is the adjacent case: an unknown error that usually means a temporary issue on Meta's side - treat it like a 5xx and simply retry with backoff, no payload changes required. Code 10 is not a throttle at all but a permission failure, so it belongs with the token and permission fixes above. Both mean throttling, not rejection of your data: Meta documents both as temporary issues to wait out or to fix by examining request volume. Conversion delivery amplifies the problem because retries collide with regular traffic - a queue that retries failed batches immediately hammers the API exactly when it is already saturated.
The mechanical fix is the same one Meta recommends for network errors: retry on non-client errors with backoff, and set a request timeout of 1,500 milliseconds - most CAPI responses arrive under 600 ms, so a longer client timeout only ties up your workers. Batch more events per request (up to 1,000 in data), and stagger scheduled jobs so several campaigns do not fire at the same second.
The 7-Day Limit and Safe Retries
The event_time rules bite late-arriving data: a server event may carry a time earlier than its send moment, but no more than 7 days back - send anything older and Meta rejects the whole request, processing none of it. Offline and physical-store events with action_source set to physical_store get a 62-day window instead. The deep case study lives in the 2804003 guide; the delay mechanics behind it are in Meta CAPI event delay.
This is also why batch retries are safe when done right. Valid events already accepted are dropped as duplicates on a resend - deduplication keys on event_id and event_name and keeps the first copy. So the correct retry loop is: fix every named invalid event, resend the whole batch, and let deduplication absorb the overlap. Never resend with regenerated event IDs - that turns the same conversion into two.
Validating Delivery After the Fixes
After the errors stop, verify what Meta actually received. Events Manager's Overview for your pixel shows raw, matched, and attributed event counts plus the connection method for each event - the gap between raw and matched is where hashing problems hide even when no error is returned. Before shipping payload changes, dry-run them in the Meta Test Events tool - it prints field-level validation without polluting production statistics.
For the structural layer around these codes - how server events relate to the pixel and when each channel fires - the Meta Conversions API complete guide maps the whole cluster, and event ID deduplication covers the anti-double-counting mechanics. If you route tracker postbacks into Meta and want the delivery automated, MOST handles retries and deduplication centrally; the free manual path lives at Pixel Activator.
