Skip to content

Editor fails to load when a cached capability flag is stale #602

Description

@dcalhoun

Description

When a host caches a site capability (shouldUseThemeStyles/themeStyles, shouldUsePlugins/plugins) and the site later loses the backing REST route, the editor fails to load with an error instead of degrading to the default experience.

The 404 is a definitive, correct answer — the route does not exist — and it's the same answer route discovery would have given had it re-run. Both platforms already have a supported "capability absent" value (EditorSettings.undefined, LocalEditorAssetManifest.empty), so this should resolve to that value rather than surfacing as an error.

The user-facing message is also WordPress's raw REST string, which is a separate problem affecting every editor load failure.

Steps to reproduce

  1. Activate the Gutenberg plugin on a test site
  2. Open the site's Editor Configuration in the Demo app — Supports Theme Styles should be ✅
  3. Deactivate the Gutenberg plugin
  4. Open the editor

Expected: editor loads with default editor styles.
Actual: an error view.

iOS: Editor Error — No route was found matching the URL and request method.
Android: Failed to load editor — rest_no_route: No route was found matching the URL and request method.

iOS Android
iOS Image

Cause

Identical on both platforms:

  1. Host caches the capability as true; the site changes underneath it without re-running discovery
  2. fetchEditorSettings no longer short-circuits and issues the request — iOS RESTAPIRepository.swift#L93-L97, Android RESTAPIRepository.kt#L88-L91
  3. WordPress returns 404 rest_no_route; the client throws a WP-error type
  4. Nothing treats it as recoverable, so it propagates out of prepare()
  5. The library's own error view renders the exception message

Proposed fix

Treat 404 rest_no_route on an optional dependency as the capability being absent:

  • iOS: RESTAPIRepository.fetchEditorSettings().undefined
  • iOS: EditorAssetLibrary.fetchManifest()LocalEditorAssetManifest.empty
  • Android: RESTAPIRepository.fetchEditorSettings()EditorSettings.undefined
  • Android: EditorAssetsLibrary.fetchManifest()LocalEditorAssetManifest.empty

Each of these already returns exactly that value when its capability flag is falseiOS settings, iOS manifest, Android settings, Android manifest. The fix extends the same outcome to the case where the endpoint itself reports the capability absent.

Scope the guard to rest_no_route specifically so genuine 404s elsewhere (e.g. a missing post) stay fatal.

This must not respect any network-fallback policy. A 404 is a successful round-trip carrying an authoritative answer; reachability policy is irrelevant. Gating it would leave hosts with fallback disabled (and all Android hosts) hitting this same wall.

Notes

  • Not demo-only. WP-Android's EditorCapabilityResolver persists capabilities across sessions — a wider staleness window than the iOS demo's per-session one. WP-iOS is likewise affected.
  • Applies equally to /wpcom/v2/editor-assets and the plugins capability.
  • The iOS demo's offline config deliberately sets both capabilities true optimistically (SitePreparationView.swift#L334-L342, from feat: improve iOS offline editor experience #366). That's safe while offline, but if connectivity returns mid-session the flags are stale in exactly this way. This fix makes that optimism safe unconditionally.
  • Impact data: wpios_gutenberg_kit_editor_load_failed / jpios_gutenberg_kit_editor_load_failed run ~5–20/day sustained. Segment by wordpress_error_code = rest_no_route to size this specific path. iOS-only — WP-Android has no equivalent instrumentation, so real impact is undercounted.
  • Surfaced while reviewing refactor: vendor the default editor styles stylesheet #600; unrelated to those changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Android[Type] BugAn existing feature does not function as intendediOS

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions