solid-start icon indicating copy to clipboard operation
solid-start copied to clipboard

Throwing or returning in redirect inside a cache function used in load results in error

Open cs-clarence opened this issue 1 year ago • 2 comments

Describe the bug

Given this code:

import { Title } from '@solidjs/meta';
import { RouteDefinition, cache, redirect } from '@solidjs/router';
import Counter from '~/components/Counter';

let isLoggedIn = false;

const redirectIfNotLoggedIn = cache(() => {
  if (!isLoggedIn) throw redirect('/login');

  return { data: 'test' };
}, 'redirect-if-not-logged-in');

export const route: RouteDefinition = {
  load: async () => await redirectIfNotLoggedIn(),
};

export default function Home() {
  return (
    <main>
      <Title>Hello World</Title>
      <h1>Hello world!</h1>
      <Counter />
      <p>
        Visit{' '}
        <a href="https://start.solidjs.com" target="_blank">
          start.solidjs.com
        </a>{' '}
        to learn how to build SolidStart apps.
      </p>
    </main>
  );
}

When returning a redirect from a cache function, this error occurs:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at __node_internal_captureLargerStackTrace2 (https://yqniqqmaogithub-cd2c.w-corp-staticblitz.com/builtins.5bf3667c.js:101:5335)
    at new NodeError (https://yqniqqmaogithub-cd2c.w-corp-staticblitz.com/builtins.5bf3667c.js:101:4149)
    at ServerResponse.setHeader (https://yqniqqmaogithub-cd2c.w-corp-staticblitz.com/builtins.5bf3667c.js:6:8796)
    at setResponseHeader (file:///home/projects/yqniqqmao.github/node_modules/h3/dist/index.mjs:908:18)
    at Module.eval (/home/projects/yqniqqmao.github/node_modules/vinxi/runtime/http.js:149:12)
    at eval (/home/projects/yqniqqmao.github/node_modules/@solidjs/start/dist/server/handler.js:101:29)
    at doShell (file:///home/projects/yqniqqmao.github/node_modules/solid-js/web/dist/server.js:358:7)
    at Object.onDone (file:///home/projects/yqniqqmao.github/node_modules/solid-js/web/dist/server.js:221:5)
    at Te.flush (file:///home/projects/yqniqqmao.github/node_modules/seroval/dist/esm/production/index.mjs:61:38999)
    at eval (file:///home/projects/yqniqqmao.github/node_modules/solid-js/web/dist/server.js:240:42) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

Node.js 18.20.3

When throwing a redirect:

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "[object Response]".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

Node.js 18.20.3

Your Example Website or App

https://stackblitz.com/edit/github-3nqamc?file=src%2Froutes%2Findex.tsx

Steps to Reproduce the Bug or Issue

  1. Run the application
  2. Visit the index route

Expected behavior

Returning/throwing a redirect in a cache function should redirect

Screenshots or Videos

No response

Platform

  • OS: Fedora Linux
  • Browser: Edge

Additional context

No response

cs-clarence avatar Jun 22 '24 08:06 cs-clarence

Likely it's because the server has already responded at the point that it resolves. If there is no async in your components then the server is going to thing it is done (or at least can stream the first chunk).. in which case by the time it tries to process the redirect it thinks it is done. There might be still a timing bug/missing guard here but we probably need to find a reproduction that reads the routes data.

ryansolid avatar Jul 02 '24 21:07 ryansolid

I'm going to move this to SolidStart because if there is an issue it makes sense to fix it is there.

ryansolid avatar Dec 11 '24 22:12 ryansolid