Skip to content

Editor exit hangs indefinitely when GutenbergView never finishes loading #22878

@jkmassel

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions