close
Skip to content

Fix: Race condition when adding multiple tags rapidly#74235

Closed
UmeraGhori wants to merge 5 commits intoWordPress:trunkfrom
UmeraGhori:fix-tag-race-condition
Closed

Fix: Race condition when adding multiple tags rapidly#74235
UmeraGhori wants to merge 5 commits intoWordPress:trunkfrom
UmeraGhori:fix-tag-race-condition

Conversation

@UmeraGhori
Copy link
Contributor

What?

I have added a debounce to the onChange handler in FlatTermSelector.

Why?

When users add multiple tags rapidly, API requests were racing against each other, causing 400 Bad Request errors and tags disappearing. This fixes issue #73782.

How?

  • Wrapped the API saving logic inside a useDebounce hook (500ms delay).
  • Optimistically updated the UI (setValues) immediately so the user experience remains fast.

Testing Instructions

  1. Open the Post Editor.
  2. Rapidly type multiple tags (e.g., tag1, tag2, tag3) hitting enter/comma quickly.
  3. Observe Network tab: Requests should be batched/delayed, and no 400 errors should occur.
  4. Refresh page to confirm tags are saved.

Fixes #73782

@github-actions github-actions bot added the [Package] Editor /packages/editor label Dec 26, 2025
@github-actions
Copy link

github-actions bot commented Dec 26, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: UmeraGhori <umeraghori@git.wordpress.org>
Co-authored-by: SirLouen <sirlouen@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
Co-authored-by: mirka <0mirka00@git.wordpress.org>
Co-authored-by: mmtr <mmtr86@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions github-actions bot added the First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository label Dec 26, 2025
@github-actions
Copy link

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @UmeraGhori! In case you missed it, we'd love to have you join us in our Slack community.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@UmeraGhori UmeraGhori force-pushed the fix-tag-race-condition branch from 9d6fb32 to 6008eea Compare December 26, 2025 23:07
@UmeraGhori
Copy link
Contributor Author

It seems the E2E tests are failing specifically on the reload check (taxonomies.spec.js).
The issue is that the test enters a tag and immediately reloads the page. Since I added a 500ms debounce, the page reloads before the debounce timer completes, so the saveEntityRecord call never happens, and the tag isn't saved.
Should I reduce the debounce time (e.g., to 250ms or 200ms), or should the test be updated to wait for the save to complete?
@SirLouen

@SirLouen SirLouen requested a review from Mamaduka December 27, 2025 00:11
@SirLouen
Copy link
Member

I think there was already a debounce for 500ms in debouncedSearch

Maybe @Mamaduka can comment a bit on this as he introduced the debounced search some time ago in #33459

@SirLouen SirLouen added [Type] Bug An existing feature does not function as intended [Package] Components /packages/components and removed [Package] Components /packages/components labels Dec 27, 2025
@UmeraGhori
Copy link
Contributor Author

Thanks for the review, @SirLouen!
You are correct that debouncedSearch exists, but it only debounces the search input query (fetching suggestions via onInputChange).
The race condition issue (#73782) happens during the selection/creation phase (the onChange handler), where rapid updates trigger multiple competing saveEntityRecord calls.
My change applies the debounce specifically to the term updates/creation logic to batch these save requests. The existing debouncedSearch doesn't cover the onChange event where the actual saving happens.

@UmeraGhori
Copy link
Contributor Author

tag.video.mp4

I updated the E2E test to explicitely wait for the API response. Since the fix introduces a debounce, the previous test was reloading the page too fast, causing a failure in the test environment. @SirLouen @Mamaduka

Copy link
Member

@SirLouen SirLouen left a comment

Choose a reason for hiding this comment

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

@UmeraGhori here are a couple of things you need to review:

First, there is something wrong with those test conditions (10s timeout is a lot so it should not be happening)
TimeoutError: page.waitForResponse: Timeout 10000ms exceeded while waiting for event "response"

It appears that the condition is never reached on time.

My best guess was that the tags are never actually being 201 created.

So I manually tested the debounce solution, and despite the idea being good, it is not working: the tags are not saved as I thought. Try to add a bunch, save, and return to the post, and you will see they are not there.

If you are planning to add some unit testing, maybe you could add a test adding 3 tags in rapid-fire succession with a similar pattern and check if all 3 with the debounce have been queried.

Also, I don't understand why the hasAssignAction should not be returned earlier.

Finally, you don't need to overcomment the code. If the code is not self-explanatory, it is generally not good.

@SirLouen SirLouen self-assigned this Jan 4, 2026
@UmeraGhori
Copy link
Contributor Author

Thanks for the review, @SirLouen! You're spot on—the debounce logic was cancelling the save requests. I'll replace it with a proper fix, move hasAssignAction for early return, and add the rapid-fire test case you suggested. Updating shortly.

@UmeraGhori
Copy link
Contributor Author

@SirLouen Thanks for the reproduction report! You were right about the API collapsing with 400 errors.

I have refactored the solution to handle this race condition:

  1. Sequential Queue: Replaced debounce with a request queue. This processes tags one-by-one, preventing the 400 errors and ensuring no data loss.
  2. Local Cache: Added a local cache to fix the "disappearing tags" issue immediately in the UI while the background requests process.
  3. Safety Lock: Implemented lockPostSaving to disable the save button while the queue is active.
  4. Test Added: Added the requested "rapid-fire" E2E test with random inputs to verify the fix.

Verified that tags now persist correctly even during rapid entry.

@Mamaduka
Copy link
Member

Mamaduka commented Jan 8, 2026

@UmeraGhori, please check the conversation in the issue. I think the fix here is getting complex for a behavior we most likely remove in the next release.

@UmeraGhori
Copy link
Contributor Author

@UmeraGhori, please check the conversation in the issue. I think the fix here is getting complex for a behavior we most likely remove in the next release.

Thanks @Mamaduka for the heads-up!

I wasn't aware that this behavior might be removed in the next release.

I will check the issue discussion as you suggested. Should I close this PR for now, or wait for a final decision on the removal?

@SirLouen SirLouen removed their assignment Feb 6, 2026
@SirLouen
Copy link
Member

SirLouen commented Feb 6, 2026

A whole new approach is going to be required for this ticket. I'm closing this PR.

@SirLouen SirLouen closed this Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] Editor /packages/editor [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tags can randomly disappear in the post editor

3 participants