Skip to content

fix: guard native inserter against non-string pattern categories#553

Open
dcalhoun wants to merge 1 commit into
trunkfrom
fix/native-inserter-non-string-pattern-categories
Open

fix: guard native inserter against non-string pattern categories#553
dcalhoun wants to merge 1 commit into
trunkfrom
fix/native-inserter-non-string-pattern-categories

Conversation

@dcalhoun

@dcalhoun dcalhoun commented Jul 16, 2026

Copy link
Copy Markdown
Member

What?

Guard against a race condition whenever opening the native block inserter quickly after editor launch. Fixes #552. Fix CMM-2168.

Why?

The race condition led to an editor crash, forcing users to close and re-open the editor.

formatPatternsForNativeInserter called cat.startsWith( '_' ) on every entry of a pattern's categories, assuming each was a slug string. For user/synced patterns this assumption can briefly break while mapUserPattern in @wordpress/block-editor builds categories by mapping each numeric wp_pattern_category term ID through the __experimentalUserPatternCategories lookup table, falling back to the raw numeric ID when that table hasn't resolved yet.

If the native inserter is opened during that gap, a category is still a number, and number.startsWith is undefined → crash (Sentry JETPACK-IOS-1KAQ). Waiting a moment lets the lookup table resolve, which is why the crash is timing-dependent.

How?

Filter categories to strings before calling startsWith. This ensures yet-to-be-resolved pattern entities with category ID numbers rather than string slugs are filtered out before performing string actions.

Testing Instructions

  1. Copy and apply the reproduction diff below ensuring the race condition state: pbpaste | git apply.
  2. Open the GutenbergKit editor and open the native block inserter.
  3. With the fix: the inserter opens normally.
  4. Temporarily drop the fix: git checkout HEAD~1 -- src/utils/blocks.js.
  5. Open the native block inserter.
  6. Without the fix: the editor displays a "The editor has encountered an unexpected error" message.
  7. Restore the fix: git checkout HEAD -- src/utils/blocks.js.
Reproduction diff
diff --git a/src/components/native-inserter/index.jsx b/src/components/native-inserter/index.jsx
index bc348fcd..65f8d92d 100644
--- a/src/components/native-inserter/index.jsx
+++ b/src/components/native-inserter/index.jsx
@@ -367,7 +367,36 @@ export default function NativeBlockInserterButton( { open, onToggle } ) {
 			categories
 		);

-		const formattedPatterns = formatPatternsForNativeInserter( patterns );
+		// TEMPORARY REPRO SHIM for JETPACK-IOS-1KAQ — DO NOT COMMIT.
+		// Forces a numeric term ID into a pattern's categories (as
+		// `mapUserPattern` does before the id→slug table resolves),
+		// nullifying the race. Synthesizes a pattern if none exist so the
+		// crash is deterministic on the first inserter open. Remove with
+		// `git checkout src/components/native-inserter/index.jsx`.
+		const reproPatterns =
+			patterns && patterns.length
+				? patterns.map( ( p, i ) =>
+						i === 0
+							? {
+									...p,
+									categories: [
+										...( p.categories ?? [] ),
+										7,
+									],
+							  }
+							: p
+				  )
+				: [
+						{
+							name: 'repro/jetpack-ios-1kaq',
+							title: 'Repro',
+							content:
+								'<!-- wp:paragraph --><p>x</p><!-- /wp:paragraph -->',
+							categories: [ 7 ], // numeric term ID, as during the race
+						},
+				  ];
+		const formattedPatterns =
+			formatPatternsForNativeInserter( reproPatterns );
 		const formattedPatternCategories =
 			formatPatternCategoriesForNativeInserter( patternCategories );

@@ -424,11 +453,9 @@ export default function NativeBlockInserterButton( { open, onToggle } ) {
 			label={ __( 'Add block' ) }
 			icon={ plus }
 			onClick={ () => {
-				// Skip the redux toggle and present the native inserter
-				// directly. Flipping `isInserterOpened` in editorStore would
-				// briefly render Gutenberg's web inserter behind the native
-				// dialog before it covers, causing a visible flash.
-				prepareAndShowInserter();
+				// Temporarily reinstate React renderer control to showcase the editor
+				// error message displayed by the ErrorBoundary component
+				onToggle( true );
 			} }
 			onMouseDown={ ( e ) => {
 				e.preventDefault();

Accessibility Testing Instructions

N/A — no UI changes. This removes a crash on an existing flow.

Screenshots or screencast

image

@dcalhoun dcalhoun added the [Type] Bug An existing feature does not function as intended label Jul 16, 2026
@github-actions github-actions Bot added the [Type] Bug An existing feature does not function as intended label Jul 16, 2026
@wpmobilebot

wpmobilebot commented Jul 16, 2026

Copy link
Copy Markdown

XCFramework Build

This PR's XCFramework is available for testing. Add the following to your Package.swift:

.package(url: "https://github.com/wordpress-mobile/GutenbergKit", branch: "pr-build/553")

Built from ab2865e

@dcalhoun
dcalhoun force-pushed the fix/native-inserter-non-string-pattern-categories branch from ab93f03 to 78f21e1 Compare July 16, 2026 18:18
`formatPatternsForNativeInserter` called `cat.startsWith( '_' )` on every
entry of a pattern's `categories`, assuming each was a slug string. User/
synced patterns can momentarily expose raw numeric term IDs instead: while
core-data resolves the id→slug lookup table, `mapUserPattern` in
`@wordpress/block-editor` falls back to returning the raw `catId` (a number).
Opening the native inserter during that resolver gap crashed with
`TypeError: cat.startsWith is not a function` (JETPACK-IOS-1KAQ).

Filter categories to strings before calling `startsWith`, and add a
regression test covering numeric/null categories.

Fixes JETPACK-IOS-1KAQ

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dcalhoun
dcalhoun force-pushed the fix/native-inserter-non-string-pattern-categories branch from 78f21e1 to ab2865e Compare July 16, 2026 18:21
@dcalhoun
dcalhoun marked this pull request as ready for review July 16, 2026 18:44
@dcalhoun
dcalhoun requested a review from jkmassel July 16, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeError: e.startsWith is not a function. (In 'e.startsWith(_)', 'e.startsWith' is undefined)

2 participants