[@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

Description

@sadnansami

Preliminary Checks

Reproduction

https://github.com/sadnansami/xcoach-clerk-middleware-issue

Publishable key

pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

Description

Package:@clerk/astro

Versions:

  • @clerk/astro: latest
  • astro: v7

Steps to reproduce:

  1. Set up an Astro project with @clerk/astro
  2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
  3. Create any Astro API route that reads the request body (e.g. await request.json())
  4. Send a POST request to that route

Expected behavior:

clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

Actual behavior:

Anything that tries to read the request body after clerkMiddleware() runs throws:

TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.

clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

Related:

This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

Environment

System:
OS: Windows 11 10.0.26200
CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
Memory: 6.19 GB / 23.87 GB
Binaries:
Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
Browsers:
Chrome: 150.0.7871.129
Edge: Chromium (150.0.4078.83)
Internet Explorer: 11.0.26100.8115
npmPackages:
@astrojs/alpinejs: ^1.0.0 => 1.0.0
@astrojs/cloudflare: ^14.1.3 => 14.1.3
@astrojs/node: ^11.0.2 => 11.0.2
@clerk/astro: ^3.4.19 => 3.4.19
@tailwindcss/vite: ^4.3.2 => 4.3.2
@types/alpinejs: ^3.13.11 => 3.13.11
@types/node: ^26.1.1 => 26.1.1
agents: ^0.17.4 => 0.17.4
alpinejs: ^3.15.12 => 3.15.12
astro: ^7.0.9 => 7.0.9
clsx: ^2.1.1 => 2.1.1
cuelume: ^0.1.2 => 0.1.2
hono: ^4.12.30 => 4.12.30
hono-agents: ^3.0.11 => 3.0.11
sonner: ^2.0.7 => 2.0.7
tailwind-merge: ^3.6.0 => 3.6.0
tailwindcss: ^4.3.2 => 4.3.2
tailwindcss-motion: ^1.1.1 => 1.1.1
tw-animate-css: ^1.4.0 => 1.4.0
wrangler: ^4.110.0 => 4.111.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageA ticket that needs to be triaged by a team member

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
       blocks
      (function() {
      function addCopyButtons() {
      document.querySelectorAll('pre code').forEach(function(codeBlock) {
      if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
      codeBlock.parentElement.setAttribute('data-copy-added', 'true');
      var btn = document.createElement('button');
      btn.textContent = 'Copy';
      btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
      btn.onmouseover = function() { this.style.opacity = '1'; };
      btn.onmouseout = function() { this.style.opacity = '0.7'; };
      btn.onclick = function() {
      navigator.clipboard.writeText(codeBlock.textContent).then(function() {
      btn.textContent = 'Copied!';
      setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
      });
      };
      codeBlock.parentElement.style.position = 'relative';
      codeBlock.parentElement.appendChild(btn);
      });
      }
      addCopyButtons();
      // Re-run on dynamic content
      var observer = new MutationObserver(addCopyButtons);
      observer.observe(document.body, { childList: true, subtree: true });
      })();
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      
      Skip to content

      [@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

      Description

      @sadnansami

      Preliminary Checks

      Reproduction

      https://github.com/sadnansami/xcoach-clerk-middleware-issue

      Publishable key

      pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

      Description

      Package:@clerk/astro

      Versions:

      • @clerk/astro: latest
      • astro: v7

      Steps to reproduce:

      1. Set up an Astro project with @clerk/astro
      2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
      3. Create any Astro API route that reads the request body (e.g. await request.json())
      4. Send a POST request to that route

      Expected behavior:

      clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

      Actual behavior:

      Anything that tries to read the request body after clerkMiddleware() runs throws:

      TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
      

      clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

      Related:

      This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

      The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

      Environment

      System:
      OS: Windows 11 10.0.26200
      CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
      Memory: 6.19 GB / 23.87 GB
      Binaries:
      Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
      Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
      npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
      pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
      bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
      Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
      Browsers:
      Chrome: 150.0.7871.129
      Edge: Chromium (150.0.4078.83)
      Internet Explorer: 11.0.26100.8115
      npmPackages:
      @astrojs/alpinejs: ^1.0.0 => 1.0.0
      @astrojs/cloudflare: ^14.1.3 => 14.1.3
      @astrojs/node: ^11.0.2 => 11.0.2
      @clerk/astro: ^3.4.19 => 3.4.19
      @tailwindcss/vite: ^4.3.2 => 4.3.2
      @types/alpinejs: ^3.13.11 => 3.13.11
      @types/node: ^26.1.1 => 26.1.1
      agents: ^0.17.4 => 0.17.4
      alpinejs: ^3.15.12 => 3.15.12
      astro: ^7.0.9 => 7.0.9
      clsx: ^2.1.1 => 2.1.1
      cuelume: ^0.1.2 => 0.1.2
      hono: ^4.12.30 => 4.12.30
      hono-agents: ^3.0.11 => 3.0.11
      sonner: ^2.0.7 => 2.0.7
      tailwind-merge: ^3.6.0 => 3.6.0
      tailwindcss: ^4.3.2 => 4.3.2
      tailwindcss-motion: ^1.1.1 => 1.1.1
      tw-animate-css: ^1.4.0 => 1.4.0
      wrangler: ^4.110.0 => 4.111.0

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        needs-triageA ticket that needs to be triaged by a team member

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          [@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

          Description

          @sadnansami

          Preliminary Checks

          Reproduction

          https://github.com/sadnansami/xcoach-clerk-middleware-issue

          Publishable key

          pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

          Description

          Package:@clerk/astro

          Versions:

          • @clerk/astro: latest
          • astro: v7

          Steps to reproduce:

          1. Set up an Astro project with @clerk/astro
          2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
          3. Create any Astro API route that reads the request body (e.g. await request.json())
          4. Send a POST request to that route

          Expected behavior:

          clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

          Actual behavior:

          Anything that tries to read the request body after clerkMiddleware() runs throws:

          TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
          

          clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

          Related:

          This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

          The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

          Environment

          System:
          OS: Windows 11 10.0.26200
          CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
          Memory: 6.19 GB / 23.87 GB
          Binaries:
          Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
          Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
          npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
          pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
          bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
          Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
          Browsers:
          Chrome: 150.0.7871.129
          Edge: Chromium (150.0.4078.83)
          Internet Explorer: 11.0.26100.8115
          npmPackages:
          @astrojs/alpinejs: ^1.0.0 => 1.0.0
          @astrojs/cloudflare: ^14.1.3 => 14.1.3
          @astrojs/node: ^11.0.2 => 11.0.2
          @clerk/astro: ^3.4.19 => 3.4.19
          @tailwindcss/vite: ^4.3.2 => 4.3.2
          @types/alpinejs: ^3.13.11 => 3.13.11
          @types/node: ^26.1.1 => 26.1.1
          agents: ^0.17.4 => 0.17.4
          alpinejs: ^3.15.12 => 3.15.12
          astro: ^7.0.9 => 7.0.9
          clsx: ^2.1.1 => 2.1.1
          cuelume: ^0.1.2 => 0.1.2
          hono: ^4.12.30 => 4.12.30
          hono-agents: ^3.0.11 => 3.0.11
          sonner: ^2.0.7 => 2.0.7
          tailwind-merge: ^3.6.0 => 3.6.0
          tailwindcss: ^4.3.2 => 4.3.2
          tailwindcss-motion: ^1.1.1 => 1.1.1
          tw-animate-css: ^1.4.0 => 1.4.0
          wrangler: ^4.110.0 => 4.111.0

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            needs-triageA ticket that needs to be triaged by a team member

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              [@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

              Description

              @sadnansami

              Preliminary Checks

              Reproduction

              https://github.com/sadnansami/xcoach-clerk-middleware-issue

              Publishable key

              pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

              Description

              Package:@clerk/astro

              Versions:

              • @clerk/astro: latest
              • astro: v7

              Steps to reproduce:

              1. Set up an Astro project with @clerk/astro
              2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
              3. Create any Astro API route that reads the request body (e.g. await request.json())
              4. Send a POST request to that route

              Expected behavior:

              clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

              Actual behavior:

              Anything that tries to read the request body after clerkMiddleware() runs throws:

              TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
              

              clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

              Related:

              This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

              The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

              Environment

              System:
              OS: Windows 11 10.0.26200
              CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
              Memory: 6.19 GB / 23.87 GB
              Binaries:
              Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
              Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
              npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
              pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
              bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
              Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
              Browsers:
              Chrome: 150.0.7871.129
              Edge: Chromium (150.0.4078.83)
              Internet Explorer: 11.0.26100.8115
              npmPackages:
              @astrojs/alpinejs: ^1.0.0 => 1.0.0
              @astrojs/cloudflare: ^14.1.3 => 14.1.3
              @astrojs/node: ^11.0.2 => 11.0.2
              @clerk/astro: ^3.4.19 => 3.4.19
              @tailwindcss/vite: ^4.3.2 => 4.3.2
              @types/alpinejs: ^3.13.11 => 3.13.11
              @types/node: ^26.1.1 => 26.1.1
              agents: ^0.17.4 => 0.17.4
              alpinejs: ^3.15.12 => 3.15.12
              astro: ^7.0.9 => 7.0.9
              clsx: ^2.1.1 => 2.1.1
              cuelume: ^0.1.2 => 0.1.2
              hono: ^4.12.30 => 4.12.30
              hono-agents: ^3.0.11 => 3.0.11
              sonner: ^2.0.7 => 2.0.7
              tailwind-merge: ^3.6.0 => 3.6.0
              tailwindcss: ^4.3.2 => 4.3.2
              tailwindcss-motion: ^1.1.1 => 1.1.1
              tw-animate-css: ^1.4.0 => 1.4.0
              wrangler: ^4.110.0 => 4.111.0

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                needs-triageA ticket that needs to be triaged by a team member

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  [@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

                  Description

                  @sadnansami

                  Preliminary Checks

                  Reproduction

                  https://github.com/sadnansami/xcoach-clerk-middleware-issue

                  Publishable key

                  pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

                  Description

                  Package:@clerk/astro

                  Versions:

                  • @clerk/astro: latest
                  • astro: v7

                  Steps to reproduce:

                  1. Set up an Astro project with @clerk/astro
                  2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
                  3. Create any Astro API route that reads the request body (e.g. await request.json())
                  4. Send a POST request to that route

                  Expected behavior:

                  clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

                  Actual behavior:

                  Anything that tries to read the request body after clerkMiddleware() runs throws:

                  TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
                  

                  clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

                  Related:

                  This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

                  The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

                  Environment

                  System:
                  OS: Windows 11 10.0.26200
                  CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
                  Memory: 6.19 GB / 23.87 GB
                  Binaries:
                  Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
                  Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
                  npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
                  pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
                  bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
                  Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
                  Browsers:
                  Chrome: 150.0.7871.129
                  Edge: Chromium (150.0.4078.83)
                  Internet Explorer: 11.0.26100.8115
                  npmPackages:
                  @astrojs/alpinejs: ^1.0.0 => 1.0.0
                  @astrojs/cloudflare: ^14.1.3 => 14.1.3
                  @astrojs/node: ^11.0.2 => 11.0.2
                  @clerk/astro: ^3.4.19 => 3.4.19
                  @tailwindcss/vite: ^4.3.2 => 4.3.2
                  @types/alpinejs: ^3.13.11 => 3.13.11
                  @types/node: ^26.1.1 => 26.1.1
                  agents: ^0.17.4 => 0.17.4
                  alpinejs: ^3.15.12 => 3.15.12
                  astro: ^7.0.9 => 7.0.9
                  clsx: ^2.1.1 => 2.1.1
                  cuelume: ^0.1.2 => 0.1.2
                  hono: ^4.12.30 => 4.12.30
                  hono-agents: ^3.0.11 => 3.0.11
                  sonner: ^2.0.7 => 2.0.7
                  tailwind-merge: ^3.6.0 => 3.6.0
                  tailwindcss: ^4.3.2 => 4.3.2
                  tailwindcss-motion: ^1.1.1 => 1.1.1
                  tw-animate-css: ^1.4.0 => 1.4.0
                  wrangler: ^4.110.0 => 4.111.0

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    needs-triageA ticket that needs to be triaged by a team member

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      [@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

                      Description

                      @sadnansami

                      Preliminary Checks

                      Reproduction

                      https://github.com/sadnansami/xcoach-clerk-middleware-issue

                      Publishable key

                      pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

                      Description

                      Package:@clerk/astro

                      Versions:

                      • @clerk/astro: latest
                      • astro: v7

                      Steps to reproduce:

                      1. Set up an Astro project with @clerk/astro
                      2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
                      3. Create any Astro API route that reads the request body (e.g. await request.json())
                      4. Send a POST request to that route

                      Expected behavior:

                      clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

                      Actual behavior:

                      Anything that tries to read the request body after clerkMiddleware() runs throws:

                      TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
                      

                      clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

                      Related:

                      This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

                      The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

                      Environment

                      System:
                      OS: Windows 11 10.0.26200
                      CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
                      Memory: 6.19 GB / 23.87 GB
                      Binaries:
                      Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
                      Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
                      npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
                      pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
                      bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
                      Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
                      Browsers:
                      Chrome: 150.0.7871.129
                      Edge: Chromium (150.0.4078.83)
                      Internet Explorer: 11.0.26100.8115
                      npmPackages:
                      @astrojs/alpinejs: ^1.0.0 => 1.0.0
                      @astrojs/cloudflare: ^14.1.3 => 14.1.3
                      @astrojs/node: ^11.0.2 => 11.0.2
                      @clerk/astro: ^3.4.19 => 3.4.19
                      @tailwindcss/vite: ^4.3.2 => 4.3.2
                      @types/alpinejs: ^3.13.11 => 3.13.11
                      @types/node: ^26.1.1 => 26.1.1
                      agents: ^0.17.4 => 0.17.4
                      alpinejs: ^3.15.12 => 3.15.12
                      astro: ^7.0.9 => 7.0.9
                      clsx: ^2.1.1 => 2.1.1
                      cuelume: ^0.1.2 => 0.1.2
                      hono: ^4.12.30 => 4.12.30
                      hono-agents: ^3.0.11 => 3.0.11
                      sonner: ^2.0.7 => 2.0.7
                      tailwind-merge: ^3.6.0 => 3.6.0
                      tailwindcss: ^4.3.2 => 4.3.2
                      tailwindcss-motion: ^1.1.1 => 1.1.1
                      tw-animate-css: ^1.4.0 => 1.4.0
                      wrangler: ^4.110.0 => 4.111.0

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        needs-triageA ticket that needs to be triaged by a team member

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          [@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

                          Description

                          @sadnansami

                          Preliminary Checks

                          Reproduction

                          https://github.com/sadnansami/xcoach-clerk-middleware-issue

                          Publishable key

                          pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

                          Description

                          Package:@clerk/astro

                          Versions:

                          • @clerk/astro: latest
                          • astro: v7

                          Steps to reproduce:

                          1. Set up an Astro project with @clerk/astro
                          2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
                          3. Create any Astro API route that reads the request body (e.g. await request.json())
                          4. Send a POST request to that route

                          Expected behavior:

                          clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

                          Actual behavior:

                          Anything that tries to read the request body after clerkMiddleware() runs throws:

                          TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
                          

                          clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

                          Related:

                          This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

                          The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

                          Environment

                          System:
                          OS: Windows 11 10.0.26200
                          CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
                          Memory: 6.19 GB / 23.87 GB
                          Binaries:
                          Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
                          Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
                          npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
                          pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
                          bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
                          Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
                          Browsers:
                          Chrome: 150.0.7871.129
                          Edge: Chromium (150.0.4078.83)
                          Internet Explorer: 11.0.26100.8115
                          npmPackages:
                          @astrojs/alpinejs: ^1.0.0 => 1.0.0
                          @astrojs/cloudflare: ^14.1.3 => 14.1.3
                          @astrojs/node: ^11.0.2 => 11.0.2
                          @clerk/astro: ^3.4.19 => 3.4.19
                          @tailwindcss/vite: ^4.3.2 => 4.3.2
                          @types/alpinejs: ^3.13.11 => 3.13.11
                          @types/node: ^26.1.1 => 26.1.1
                          agents: ^0.17.4 => 0.17.4
                          alpinejs: ^3.15.12 => 3.15.12
                          astro: ^7.0.9 => 7.0.9
                          clsx: ^2.1.1 => 2.1.1
                          cuelume: ^0.1.2 => 0.1.2
                          hono: ^4.12.30 => 4.12.30
                          hono-agents: ^3.0.11 => 3.0.11
                          sonner: ^2.0.7 => 2.0.7
                          tailwind-merge: ^3.6.0 => 3.6.0
                          tailwindcss: ^4.3.2 => 4.3.2
                          tailwindcss-motion: ^1.1.1 => 1.1.1
                          tw-animate-css: ^1.4.0 => 1.4.0
                          wrangler: ^4.110.0 => 4.111.0

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            needs-triageA ticket that needs to be triaged by a team member

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              [@clerk/astro] clerkMiddleware() consumes request body, breaking Cloudflare Durable Objects / downstream body reads #9210

                              Description

                              @sadnansami

                              Preliminary Checks

                              Reproduction

                              https://github.com/sadnansami/xcoach-clerk-middleware-issue

                              Publishable key

                              pk_test_YnJhdmUtcGVyY2gtNy5jbGVyay5hY2NvdW50cy5kZXYk

                              Description

                              Package:@clerk/astro

                              Versions:

                              • @clerk/astro: latest
                              • astro: v7

                              Steps to reproduce:

                              1. Set up an Astro project with @clerk/astro
                              2. Add clerkMiddleware() as the Astro onRequest handler in src/middleware.ts
                              3. Create any Astro API route that reads the request body (e.g. await request.json())
                              4. Send a POST request to that route

                              Expected behavior:

                              clerkMiddleware() should authenticate the request without consuming it, so anything downstream — an Astro API route, an adapter, or any other middleware — can still read the body.

                              Actual behavior:

                              Anything that tries to read the request body after clerkMiddleware() runs throws:

                              TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
                              

                              clerkMiddleware() drains the request body during authentication. This is not specific to any adapter or runtime — it affects any downstream consumer of the request body.

                              Related:

                              This exact bug was already fixed for @clerk/tanstack-react-start in PR #7020 (Oct 2025), which resolved issue #7019. The fix wraps the incoming request with patchRequest into a ClerkRequest to avoid consuming the body, taking inspiration from the existing implementation in @clerk/react-router.

                              The same fix needs to be ported to @clerk/astro's clerkMiddleware. The pattern and precedent are already established in the codebase.

                              Environment

                              System:
                              OS: Windows 11 10.0.26200
                              CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
                              Memory: 6.19 GB / 23.87 GB
                              Binaries:
                              Node: 24.14.0 - C:\Program Files\nodejs\node.EXE
                              Yarn: 1.22.22 - C:\Users\S. Adnan Sami\AppData\Local\pnpm\yarn.CMD
                              npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD
                              pnpm: 9.11.0 - C:\Program Files\nodejs\pnpm.CMD
                              bun: 1.3.11 - C:\Users\S. Adnan Sami\.bun\bin\bun.EXE
                              Deno: 2.7.5 - C:\Users\S. Adnan Sami\.deno\bin\deno.EXE
                              Browsers:
                              Chrome: 150.0.7871.129
                              Edge: Chromium (150.0.4078.83)
                              Internet Explorer: 11.0.26100.8115
                              npmPackages:
                              @astrojs/alpinejs: ^1.0.0 => 1.0.0
                              @astrojs/cloudflare: ^14.1.3 => 14.1.3
                              @astrojs/node: ^11.0.2 => 11.0.2
                              @clerk/astro: ^3.4.19 => 3.4.19
                              @tailwindcss/vite: ^4.3.2 => 4.3.2
                              @types/alpinejs: ^3.13.11 => 3.13.11
                              @types/node: ^26.1.1 => 26.1.1
                              agents: ^0.17.4 => 0.17.4
                              alpinejs: ^3.15.12 => 3.15.12
                              astro: ^7.0.9 => 7.0.9
                              clsx: ^2.1.1 => 2.1.1
                              cuelume: ^0.1.2 => 0.1.2
                              hono: ^4.12.30 => 4.12.30
                              hono-agents: ^3.0.11 => 3.0.11
                              sonner: ^2.0.7 => 2.0.7
                              tailwind-merge: ^3.6.0 => 3.6.0
                              tailwindcss: ^4.3.2 => 4.3.2
                              tailwindcss-motion: ^1.1.1 => 1.1.1
                              tw-animate-css: ^1.4.0 => 1.4.0
                              wrangler: ^4.110.0 => 4.111.0

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                needs-triageA ticket that needs to be triaged by a team member

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions