Skip to content

Fix false "XML-RPC Disabled" card on rate-limited self-hosted sites - #23120

Merged
adalpari merged 3 commits into
trunkfrom
fix/xmlrpc-disabled-card-rate-limit-false-positive
Jul 21, 2026
Merged

Fix false "XML-RPC Disabled" card on rate-limited self-hosted sites#23120
adalpari merged 3 commits into
trunkfrom
fix/xmlrpc-disabled-card-rate-limit-false-positive

Conversation

@adalpari

@adalpari adalpari commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Description

App-password self-hosted sites could wrongly show the "XML-RPC Disabled" My Site card even when XML-RPC is actually enabled. The root cause: a transient HTTP 429 (rate-limit) from the site's xmlrpc.php was treated as "XML-RPC unavailable" in two places.

1. Discovery succeeds at login, then the authenticated XML-RPC fetch 429s. SiteStore.fetchSitesXmlRpcFromApplicationPassword fell back to the WPAPI path and discarded the already-verified endpoint. It now persists the verified endpoint on the WPAPI-stored site via the new URL-keyed SiteSqlUtils.updateXmlRpcUrlForWPAPISite (ORIGIN_WPAPI-scoped, mirroring updateWpApiRestUrlForWPAPISite).

2. Discovery itself 429s. DiscoveryXMLRPCClient.listMethods silently swallowed the 429 as an empty response, so discovery reported MISSING_XMLRPC_METHOD / NO_SITE_ERROR — indistinguishable from a genuinely disabled site. A new DiscoveryError.RATE_LIMITED is now thrown on 429 and propagated through verifyXMLRPCUrl / checkXMLRPCEndpointValidity.
⚠️ Gotcha: Volley's ClientError (429) extends ServerError, so the 429 has to be handled inside the ServerError branch, before the 405 check.

Card behavior. ApplicationPasswordViewModelSlice no longer shows the warning optimistically. attemptXmlRpcRediscovery surfaces the card only on a definitive negative discovery result (NO_SITE_ERROR, MISSING_XMLRPC_METHOD, XMLRPC_BLOCKED, XMLRPC_FORBIDDEN); transient/unknown failures keep it hidden and re-check on the next refresh. It also bails on the first 429 instead of firing a burst of discovery requests that re-trigger the rate limit.

Genuine detection is preserved: a truly disabled site (clean 404/405/403, no 429) still surfaces the warning.

Testing instructions

XML-RPC card is not falsely shown on a rate-limited site:

  1. Create a fresh WordPress site on jurassic.ninja (these sandbox sites aggressively rate-limit xmlrpc.php with HTTP 429).
  2. Confirm XML-RPC is enabled on the site (it is by default).
  3. In the app, log in to that site via Application Password (enter the site URL and authorize).
  4. Open the My Site screen for that site.
  • Verify the "XML-RPC Disabled" card is not shown.

Genuine "disabled" detection still works:

  1. Log in (app password) to a self-hosted site that has XML-RPC actually disabled (e.g. https://xmlrpc-disabled-by-plugin.wpmt.co/).
  2. Open the My Site screen.
  • Verify the "XML-RPC Disabled" card is shown. NOTE: Card can appear/dissapear due to multiple retries, but the final state must be shown.
Screenshot 2026-07-21 at 10 54 57

App-password self-hosted sites could wrongly show the "XML-RPC Disabled"
My Site card even when XML-RPC is enabled, because a transient HTTP 429
(rate-limit) was treated as "XML-RPC unavailable" in two places:

1. Discovery succeeds at login but the authenticated XML-RPC fetch 429s:
   fetchSitesXmlRpcFromApplicationPassword fell back to WPAPI and dropped
   the already-verified endpoint. Now it persists the verified endpoint on
   the WPAPI-stored site via the new URL-keyed updateXmlRpcUrlForWPAPISite.

2. Discovery itself 429s: DiscoveryXMLRPCClient.listMethods swallowed the
   429 as an empty response, so discovery reported MISSING_XMLRPC_METHOD /
   NO_SITE_ERROR, indistinguishable from a genuinely disabled site. (Note:
   Volley's ClientError for 429 extends ServerError, so the 429 must be
   handled inside the ServerError branch.) A new DiscoveryError.RATE_LIMITED
   is now thrown and propagated through verifyXMLRPCUrl /
   checkXMLRPCEndpointValidity.

The card slice no longer shows the warning optimistically:
attemptXmlRpcRediscovery surfaces the card only on a definitive-negative
discovery result (NO_SITE_ERROR, MISSING_XMLRPC_METHOD, XMLRPC_BLOCKED,
XMLRPC_FORBIDDEN); transient/unknown failures keep it hidden and re-check
on the next refresh. It also bails on the first 429 instead of firing a
burst of discovery requests that re-trigger the rate limit.

Genuine detection is preserved: a truly disabled site (clean 404/405/403,
no 429) still surfaces the warning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dangermattic

dangermattic commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator
1 Warning
⚠️ PR is not assigned to a milestone.

Generated by 🚫 Danger

@wpmobilebot

wpmobilebot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

App Icon📲 You can test the changes from this Pull Request in WordPress Android by scanning the QR code below to install the corresponding build.

App NameWordPress Android
Build TypeDebug
Versionpr23120-5abca4d
Build Number1498
Application IDorg.wordpress.android.prealpha
Commit5abca4d
Installation URL5prk0k62c4lrg
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

wpmobilebot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

App Icon📲 You can test the changes from this Pull Request in Jetpack Android by scanning the QR code below to install the corresponding build.

App NameJetpack Android
Build TypeDebug
Versionpr23120-5abca4d
Build Number1498
Application IDcom.jetpack.android.prealpha
Commit5abca4d
Installation URL6ddoembl05aig
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.69697% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.71%. Comparing base (8abbdf1) to head (5abca4d).
⚠️ Report is 1 commits behind head on trunk.

Files with missing lines Patch % Lines
...ationpassword/ApplicationPasswordViewModelSlice.kt 80.95% 1 Missing and 3 partials ⚠️
...xc/network/discovery/SelfHostedEndpointFinder.java 0.00% 4 Missing ⚠️
...fluxc/network/discovery/DiscoveryXMLRPCClient.java 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            trunk   #23120      +/-   ##
==========================================
+ Coverage   37.68%   37.71%   +0.02%     
==========================================
  Files        2343     2343              
  Lines      127342   127365      +23     
  Branches    17658    17667       +9     
==========================================
+ Hits        47995    48033      +38     
+ Misses      75414    75394      -20     
- Partials     3933     3938       +5     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@adalpari
adalpari marked this pull request as ready for review July 21, 2026 09:11
@adalpari
adalpari requested a review from nbradbury July 21, 2026 09:12

@nbradbury nbradbury left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is good :shipit:

@adalpari
adalpari enabled auto-merge (squash) July 21, 2026 11:25
@adalpari
adalpari merged commit c3f35fb into trunk Jul 21, 2026
21 of 23 checks passed
@adalpari
adalpari deleted the fix/xmlrpc-disabled-card-rate-limit-false-positive branch July 21, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants