Skip to content

Editor exit hangs indefinitely when GutenbergView never finishes loading #22878

Description

@jkmassel

Summary

If GutenbergView never finishes loading (e.g. an upstream 404 on wp-block-editor/v1/settings, network failure mid-init, or any other case where the JS bridge never becomes available), the editor activity gets stuck — back press doesn't dismiss it, the "saving" progress dialog stays open, and the only way out is to force-stop the app.

Repro

Surfaced while testing #22579 against a WP.com Atomic site (automatticwidgets.wpcomstaging.com, Storefront theme) where wp-block-editor/v1/settings returns 404 and GutenbergView stalls at progress 81/100.

  1. Open the editor on a site where the underlying GBKit init can't complete
  2. Wait for the editor to stall (visible: progress bar never advances past loading)
  3. Tap the X / back button
  4. Nothing happens — saving dialog appears and the activity never finishes

Root cause

GutenbergKitEditorFragment.getTitleAndContent blocks on CountDownLatch.await() with no timeout:

val latch = CountDownLatch(1)
gutenbergView.getTitleAndContent(originalContent, object : TitleAndContentCallback {
    override fun onResult(title, content) {
        result[0] = Pair(title, content)
        latch.countDown()
    }
}, completeComposition)

val finalResult = try {
    latch.await()  // never returns if the bridge never replies
    result[0]
} catch (e: InterruptedException) { ... }

The save-on-exit flow (savePostAndOptionallyFinishupdateAndSavePostAsyncOnEditorExitupdateAndSavePostAsyncupdateFromEditorgetTitleAndContent) sits on this latch waiting for TitleAndContentCallback.onResult to fire from JS. When GutenbergView hasn't finished loading, the bridge call is dropped silently — GBKit internally guards on its private isEditorLoaded field and logs "You can't change the editor content until it has loaded". latch.countDown() never fires; the completion lambda that would call storePostViewModel.finish(it) never runs; the activity never finishes.

Introduced incidentally by #22764 ("Upgrade GutenbergKit from v0.11.1 to v0.15.2"), which switched the bridge call from sync to async-with-latch.

Proposed fix

Two layers, both host-side. GBKit doesn't currently expose a public ready-state property — only the setEditorDidBecomeAvailable {} callback.

  1. Track ready state in the fragment. Flip a local editorReady flag to true inside the setEditorDidBecomeAvailable {} listener we already register. Short-circuit getTitleAndContent to return Pair("", "") when the flag is false.
  2. Bound the latch. Replace latch.await() with latch.await(N, TimeUnit.SECONDS) (5s is probably reasonable) as a belt-and-braces guard for any race window. On timeout, return the same Pair("", "") fallback.

Net behaviour: editor stall → empty title/content on exit → no save attempted → activity finishes immediately. Honest outcome for a session where nothing was loaded.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions