Skip to content

Bug Report: reactStartHandler fails with AbortError due to missing duplex option #118

@mez

Description

@mez

Environment

  • Package: @convex-dev/[email protected]
  • Framework: TanStack Start ^1.132.27
  • Node.js: ^20.19.9 (with modern Fetch API)
  • Runtime: Node.js server-side handlers

Description

The reactStartHandler function fails with an AbortError when proxying POST requests with a body to Convex. The error occurs
because the implementation is missing the required duplex option when creating a new Request object with a streaming body.

export const reactStartHandler = (request, opts) => {
      const requestUrl = new URL(request.url);
      const convexSiteUrl = opts?.convexSiteUrl ?? process.env.VITE_CONVEX_SITE_URL;
      if (!convexSiteUrl) {
          throw new Error("VITE_CONVEX_SITE_URL is not set");
      }
      const nextUrl = `${convexSiteUrl}${requestUrl.pathname}${requestUrl.search}`;
      request.headers.set("accept-encoding", "application/json"); // ← Issue #1: immutable headers
      return fetch(nextUrl, new Request(request, { redirect: "manual" })); // ← Issue #2: missing duplex
  };

Reproduction

  // apps/web/src/routes/api/auth/$.ts
  import { createFileRoute } from "@tanstack/react-router";
  import { reactStartHandler } from "@convex-dev/better-auth/react-start";

  export const Route = createFileRoute("/api/auth/$")({
    server: {
      handlers: {
        POST: async ({ request }) => {
          const convexSiteUrl = process.env.CONVEX_SITE_URL;
          return reactStartHandler(request, { convexSiteUrl });
        },
      },
    },
  });

Try to sign up via POST to /api/auth/sign-up/email - it will fail with AbortError.

Suggested Fix (** with claude's help **)

  export const reactStartHandler = (request: Request, opts?: { convexSiteUrl?: string; verbose?: boolean }) => {
      const requestUrl = new URL(request.url);
      const convexSiteUrl = opts?.convexSiteUrl ?? process.env.VITE_CONVEX_SITE_URL;
      if (!convexSiteUrl) {
          throw new Error("VITE_CONVEX_SITE_URL is not set");
      }
      const nextUrl = `${convexSiteUrl}${requestUrl.pathname}${requestUrl.search}`;

      // Create mutable headers
      const headers = new Headers(request.headers);
      headers.set("accept-encoding", "application/json");

      // Include duplex option for streaming bodies
      return fetch(nextUrl, {
          method: request.method,
          headers: headers,
          body: request.method !== 'GET' && request.method !== 'HEAD' ? request.body : undefined,
          redirect: "manual",
          // @ts-ignore - duplex is required for streaming request bodies in modern fetch
          duplex: 'half',
      });
  };

My current Workaround

Manually implement the proxy handler.

If you confirm this I can submit a pull request with the update!

return fetch(nextUrl, new Request(request, { redirect: "manual" }));

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions