diff --git a/core/modules/system/js/auction_bid.js b/core/modules/system/js/auction_bid.js
new file mode 100644
index 00000000000..6c9e0ea4d89
--- /dev/null
+++ b/core/modules/system/js/auction_bid.js
@@ -0,0 +1,46 @@
+(function (Drupal, once) {
+  Drupal.behaviors.auctionBidCount = {
+    attach(context) {
+      once('auction-bid', '#auction-bid-submit', context).forEach((el) => {
+        el.addEventListener('click', (e) => {
+          e.preventDefault();
+
+          const form = el.closest('form');
+          const amount = form.querySelector('input[name="bid_amount"]').value;
+
+          // Manual fetch call to trigger the AJAX callback.
+          fetch('/system/bid-ajax-callback', {
+            method: 'POST',
+            headers: {
+              'Content-Type': 'application/x-www-form-urlencoded',
+              'X-Requested-With': 'XMLHttpRequest',
+            },
+            body: `amount=${amount}`,
+          })
+            .then((response) => {
+              if (!response.ok) {
+                // If not 200, we expect core's AJAX error handler to catch this IF we were using Drupal.ajax.
+                // But here we are manually fetching.
+                // To simulate the bug, we WANT to see if core's global error handler triggers.
+                // However, core's global handler usually only triggers on unhandled exceptions or specific Drupal.ajax failures.
+                return response.json().then((data) => {
+                  console.log(data);
+                  throw new Error(data.message || 'Unknown error');
+                });
+              }
+              return response.json();
+            })
+            .then((data) => {
+              alert(`Success: ${data.message}`);
+            })
+            .catch((error) => {
+              console.log(error);
+              // This is where we manually show the error.
+              // IF the bug is that Drupal's global handler ALSO shows an error, it will appear twice.
+              alert(`Manual Error: ${error.message}`);
+            });
+        });
+      });
+    },
+  };
+})(Drupal, once);
diff --git a/core/modules/system/src/Form/AuctionBidForm.php b/core/modules/system/src/Form/AuctionBidForm.php
new file mode 100644
index 00000000000..79ff9e5128a
--- /dev/null
+++ b/core/modules/system/src/Form/AuctionBidForm.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Drupal\system\Form;
+
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides an auction bid form.
+ */
+class AuctionBidForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'system_auction_bid_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $form['bid_amount'] = [
+      '#type' => 'number',
+      '#title' => $this->t('Bid Amount'),
+      '#required' => TRUE,
+    ];
+
+    $form['actions'] = [
+      '#type' => 'actions',
+    ];
+
+    $form['actions']['submit'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Bid'),
+      '#attributes' => [
+        'id' => 'auction-bid-submit',
+      ],
+    ];
+
+    $form['#attached']['library'][] = 'system/auction_bid';
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    // This is handled by AJAX.
+  }
+
+}
diff --git a/core/modules/system/src/SystemManager.php b/core/modules/system/src/SystemManager.php
index fd5a0f6a2ab..d48fba583bd 100644
--- a/core/modules/system/src/SystemManager.php
+++ b/core/modules/system/src/SystemManager.php
@@ -8,6 +8,8 @@
 use Drupal\Core\Menu\MenuLinkInterface;
 use Drupal\Core\Menu\MenuLinkTreeInterface;
 use Drupal\Core\Menu\MenuTreeParameters;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\Request;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\HttpFoundation\RequestStack;
 
@@ -178,4 +180,24 @@ public function getAdminBlock(MenuLinkInterface $instance) {
     return $content;
   }
 
+  /**
+   * AJAX callback for auction bid simulation.
+   */
+  public function bidAjaxCallback(Request $request) {
+    $amount = (int) $request->request->get('amount');
+
+    // Simulate different errors.
+    if ($amount === 1) {
+      return new JsonResponse(['message' => 'Not enough credits'], 403);
+    }
+    if ($amount === 2) {
+      return new JsonResponse(['message' => 'Your daily limit of bid has been reached'], 429);
+    }
+    if ($amount === 3) {
+      return new JsonResponse(['message' => 'Your bid is under the current higher bid'], 409);
+    }
+
+    return new JsonResponse(['message' => 'Bid successfully placed']);
+  }
+
 }
diff --git a/core/modules/system/system.libraries.yml b/core/modules/system/system.libraries.yml
index 6667ad55b21..76e964655e7 100644
--- a/core/modules/system/system.libraries.yml
+++ b/core/modules/system/system.libraries.yml
@@ -71,3 +71,10 @@ drupal.system.date:
     - core/drupalSettings
     - core/once
     - core/drupal.form
+
+auction_bid:
+  js:
+    js/auction_bid.js: {}
+  dependencies:
+    - core/drupal
+    - core/once
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index f9b690a1493..3f5a5f04ed4 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -529,3 +529,18 @@ system.linkset_settings:
 route_callbacks:
   - '\Drupal\system\Routing\AssetRoutes::routes'
   - '\Drupal\system\Routing\MenuLinksetRoutes::routes'
+
+system.auction_bid:
+  path: '/system/auction-bid'
+  defaults:
+    _form: '\Drupal\system\Form\AuctionBidForm'
+    _title: 'Auction Bid'
+  requirements:
+    _permission: 'access content'
+
+system.bid_ajax_callback:
+  path: '/system/bid-ajax-callback'
+  defaults:
+    _controller: 'system.manager:bidAjaxCallback'
+  requirements:
+    _permission: 'access content'
