Skip to content

fix(facebook): map five recurring Graph API rejections instead of "Unknown Error" - #2127

Merged
giladresisi merged 2 commits into
mainfrom
fix/facebook-error-mappings-main
Sep 23, 2026
Merged

giladresisi merged 2 commits into
mainfrom
fix/facebook-error-mappings-main

Conversation

@giladresisi

Copy link
Copy Markdown
Collaborator

Replaces #2045 (same change, rebased onto main).

What kind of change does this PR introduce?

Bug fix (backend, Facebook provider error mapping). Adds five branches to handleErrors in facebook.provider.ts so responses that today surface as "Unknown Error" get a readable message and the right outcome:

  • 190 / subcode 459 (user checkpointed): bad-body, tells the user to log in at facebook.com and resolve the security check.
  • 190 / subcode 492 (no role on the Page): bad-body, tells the user to get a Page role from an admin, then reconnect.
  • 190 "Any of the pages_read_engagement, ... permission(s) must be granted before impersonating a user's page": refresh-token, so the channel is flagged for reconnection with all permissions.
  • 100 / subcode 33 "Object with ID ... does not exist": bad-body, the target Page or post is gone, no point retrying.
  • Facebook's HTML outage page ("Sorry, something went wrong. We're working on it"): retry.

The retry type is added to the method's return union. The new branches sit before the existing loose '490' substring match so it cannot swallow them. No existing mapping changed, and the generic fetch/retry logic in social.abstract.ts is untouched.

Why was this change needed?

The production Errors table has 1,827 Facebook rows in the last 45 days whose only message is "Unknown Error". Decoding the raw Graph API bodies stored in the failure details shows they are a handful of well-defined responses. The five mapped here account for 655 of them:

  • 318 are 100/33 "does not exist". Almost all target an integration that was soft-deleted and re-added, so the stored page id no longer exists on Facebook. These were being retried for nothing. Blocking post creation on deleted channels landed in fix(posts): reject post creation on soft-deleted channels #1921; the workflow-side guard on integration.deletedAt is deliberately left for the next workflow version bump.
  • 190 are the missing pages_* permissions body. Meta's error reference lists code 200-299 / missing permissions as "handle the missing permissions", which for us means re-granting them in the login dialog, hence refresh-token.
  • 52 are 190/492 and 45 are 190/459. Per Meta's error reference these need the user to fix a Page role or a checkpoint on Facebook itself, so a reconnect prompt would be misleading; they now fail with the Facebook-side instruction.
  • 50 are the HTML outage page. It has no JSON message, so it could never be mapped by code; the visible text is stable and Meta's guidance for its downtime codes is to wait and retry.

The rest of the "Unknown Error" volume is the "Page not accessible" token error (#1881) and the (#200) permission family (#1892), both already merged into main. The (#200) branch sits ahead of the new permissions branch in handleErrors, so (#200) bodies that merely list permission names keep their curated message.

Meta error reference: https://developers.facebook.com/docs/graph-api/guides/error-handling

Other information:

Verified by running the updated handleErrors against every distinct Facebook "Unknown Error" body from production in the last 45 days: the five responses above map to the intended type and message, every other body still returns undefined, and all pre-existing mappings produce the same results as before. tsc on nestjs-libraries reports no new errors.

QA

  1. In libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts, call new FacebookProvider().handleErrors(body, 400) (for example from a scratch ts-node script at the repo root) with {"error":{"message":"x","code":190,"error_subcode":459}}; expect type: 'bad-body' and a message about resolving a security check at facebook.com.
  2. Same call with {"error":{"message":"x","code":190,"error_subcode":492}}; expect type: 'bad-body' and a message about needing a role on the Page.
  3. Same call with {"error":{"message":"Any of the pages_read_engagement, pages_manage_metadata permission(s) must be granted before impersonating a user's page.","code":190}}; expect type: 'refresh-token'.
  4. Same call with {"error":{"message":"Unsupported post request. Object with ID '123' does not exist, cannot be loaded due to missing permissions, or does not support this operation.","code":100,"error_subcode":33}}; expect type: 'bad-body' and a message saying the target no longer exists.
  5. Same call with the string <html><title>Facebook | Error</title><body>Sorry, something went wrong. We're working on it and we'll get it fixed as soon as we can.</body></html>; expect type: 'retry'.
  6. Same call with {"error":{"message":"(#200) If posting to a group, requires app being installed in the group, and either publish_to_groups permission with user token, or pages_read_engagement","code":200}}; expect undefined (the permissions branch must not catch (#200) bodies that merely list permission names).
  7. Same call with {"error":{"message":"Error validating access token","code":190}}; expect the pre-existing refresh-token result, unchanged.
  8. Optional end to end: connect a Facebook Page, delete the channel from the dashboard while a post is still scheduled to it, then re-add the same Page. When the old post runs, the calendar tooltip shows the "no longer exists" message and the workflow does not retry the activity.

Checklist:

Put a "X" in the boxes below to indicate you have followed the checklist;

  • I have read the CONTRIBUTING guide.
  • I have signed the Contributor License Agreement (CLA) (ICLA for individuals, CCLA for entities).
  • I confirm I have not used AI to submit this PR or generate code for it.
  • I checked that there were no similar issues or PRs already open for this.
  • This PR fixes just ONE issue
  • I have filled in the QA section above with real steps to verify this change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GBHogYQMvY5zHT7qkdUQAT

…known Error"

Adds handleErrors branches for 190/459 (checkpoint), 190/492 (no Page role),
the 190 missing pages_* permissions body, 100/33 object does not exist, and
Facebook's HTML outage page, so users see the reason and the right outcome
(fail, reconnect, or retry) instead of "Unknown Error".
"error_subcode":33 as a substring also matched 330 and 331; the same held for
459 and 492. Test the three subcodes with a trailing word boundary instead.
@strix-security

strix-security Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Strix Security Review

No security issues found.

Review summary

Reviewed the single changed file, libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts. The PR adds five error-mapping branches to handleErrors and widens its return union with retry. All new branches match the Facebook Graph API response body using fixed indexOf literals or simple fixed-literal regexes (no backtracking-prone patterns, so no ReDoS). Returned messages are hardcoded constants with no reflection of attacker-controlled data (no XSS or injection). No authentication, authorization, secret, cryptographic, file, or network logic is introduced or weakened. The retry type was already present in the base handleErrors union in social.abstract.ts and is already handled by the consuming fetch/retry logic, so the widened return type is consistent. No security issues were identified in the changed code.

Updated for 8b5999b.


Reviewed by Strix
Re-run review · Configure security review settings

@postiz-agent

postiz-agent Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues
✅ Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@giladresisi
giladresisi added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit 5f8639b Sep 23, 2026
13 of 14 checks passed
@giladresisi
giladresisi deleted the fix/facebook-error-mappings-main branch September 23, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant