Next.js Discord

Discord Forum

SSL wrong version number after switching between route groups

Unanswered
Black carpenter ant posted this in #help-forum
Open in Discord
Black carpenter antOP
I am handling auth using route groups and upon logging out, I get the following error:
failed to get redirect response TypeError: fetch failed
     at node:internal/deps/undici/undici:12618:11
     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
     at async globalThis.fetch (/workspace/.next/server/chunks/6225.js:1:38529)
     at async rp (/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:15:4325)
     at async rm (/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:16:741)
     at async rq (/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:18:1249)
     at async doRender (/workspace/node_modules/next/dist/server/base-server.js:1376:30)
     at async cacheEntry.responseCache.get.routeKind (/workspace/node_modules/next/dist/server/base-server.js:1537:28)
     at async NextNodeServer.renderToResponseWithComponentsImpl (/workspace/node_modules/next/dist/server/base-server.js:1445:28)
     at async NextNodeServer.renderPageComponent (/workspace/node_modules/next/dist/server/base-server.js:1842:24) {
   cause: [Error: 40380321C27E0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:354:
   ] {
     library: 'SSL routines',
     reason: 'wrong version number',
     code: 'ERR_SSL_WRONG_VERSION_NUMBER'
   }
}


After I get this error, all of my requests return the same error but before changing the route group I don't get the error when doing the same requests.

69 Replies

Black carpenter antOP
I am handling the change of route groups in my middleware based on the presence of a cookie and all the logout button does is remove the cookie using a server action

export async function middleware(request: NextRequest) {
  const session = request.cookies.get('kc_session');
  const { pathname, search } = request.nextUrl;

  if (pathname.startsWith('/legal')) {
    return NextResponse.next();
  }

  if (pathname.startsWith('/_next')) {
    return NextResponse.next();
  }

  try {
    if (!session) {
      throw new Error('Unauthorized');
    }

    return NextResponse.rewrite(
      new URL(`/auth${pathname}${search}`, request.url),
    );
  } catch {
    return NextResponse.rewrite(
      new URL(`/noAuth${pathname}${search}`, request.url),
    );
  }
}
All of this is working without issue when running locally but when I deploy it to DigitalOcean App Platform I start to face this issue
Black carpenter antOP
It’s hosted using App Platform which is the PaaS, it uses heroku-buildpack-nodejs but I can’t find anything more specific as to what else they might use
@Black carpenter ant It’s hosted using App Platform which is the PaaS, it uses heroku-buildpack-nodejs but I can’t find anything more specific as to what else they might use
oh I have never used it, do you need to set anything?
and could you try to add a console.log(request.url) in the middleware?
Black carpenter antOP
All I need to do it push to GitHub and then it pulls the repo, builds and runs it. I've never had this issue in the past when deploying Next on App Platform and the only difference I think is the route groups. I'm just deploying the log change to see what it gives me
@Ray oh I have never used it, do you need to set anything? and could you try to add a `console.log(request.url)` in the middleware?
Black carpenter antOP
The URL just before the error appears is https://0.0.0.0:8080/login
And now I'm getting the error Error: Failed to find Server Action after the original error appears
@Black carpenter ant The URL just before the error appears is `https://0.0.0.0:8080/login`
Could you try to get the domain with request.header.get(“host”)?
and do
const proto = new URL(request).protocol
const host = request.header.get(“host”)
NextResponse.rewrite(‘${proto}//${host}/login’)
@Black carpenter ant I end up with a 404 because the login is within a route group
Hmm could you try to adjust the pathname because I dont know how your routing look like
Black carpenter antOP
Yeah, I'm just trying that now, just waiting for it to deploy
It looks like it acts as a redirect and I'm not sure why. I'll visit / and because there's no cookie it'll redirect to /noAuth instead of doing it like is did previously with the rewrite and then it just ends up in a massive loop of /noAuth/noAuth/.../noAuth etc.
@Ray Could you try again with this NextResponse.rewrite(new URL(‘${proto}//${host}/pathname’))
Black carpenter antOP
Still getting the same loop issue
@Black carpenter ant Still getting the same loop issue
Hmm, let me try to deploy a site to it
Black carpenter antOP
I don't think I do have any other Next sites using rewrites on this platform, no
I'm not sure if this is relevant, but the host from the headers is still the original domain while the request.url is showing 0.0.0.0 so that might be the cause of the loop
Black carpenter antOP
So the site loads under the noAuth rewrite but when I try to login, it sets the cookie as it should which changes to the auth rewrite except the rewrite doesn’t work, I get stuck on the noAuth pages and that’s when the SSL error happens
Black carpenter antOP
I'm no longer getting the SSL error after doing that but I'm still getting the Failed to find Server Action error. I think the SSL error isn't happening because I can't call the login server action which is what causes the change in rewrite
@Ray What is your next version?
Black carpenter antOP
14.1.2
@Black carpenter ant 14.1.2
Could you show the code of the action?
@Ray Could you show the code of the action?
Black carpenter antOP
Yeah, I've taken out the calls to my database but this is the rest of the action
export async function signin(formData: FormData) {
  const email = formData.get('email');
  const password = formData.get('password');

  if (!email || email === '') {
    throw new Error('Email is required');
  }

  if (!password || password === '') {
    throw new Error('Password is required');
  }

  try {
    const session = // Call to database that returns object

    cookies().set(SESSION_COOKIE, session.secret, {
      path: '/',
      httpOnly: true,
      sameSite: 'strict',
      secure: true,
    });
  } catch (error) {
    console.error(error);
    throw new Error('Failed to sign in');
  } finally {
    redirect('/');
  }
}
Black carpenter antOP
No, I'm using Appwrite, it's a Firebase alternative
Ah
@Black carpenter ant No, I'm using Appwrite, it's a Firebase alternative
Are you importing the action from client component?
Black carpenter antOP
This specific action is being imported to a server component
Black carpenter antOP
After adding the if (request.method === 'POST') return; it stops working on dev, but without it there's no problems
Black carpenter antOP
No, it still can't find the server action
I think the server action might need to rewrite as well because it's trying to post to /login which is meant to rewrite to /noAuth/login
Oh you are on /noAuth/login/page.tsx?
Black carpenter antOP
Yeah, so the page is located at /noAuth/login/page.tsx but it’s meant to be rewritten to /login/page.tsx
It all works until the rewrite changes to /auth/page.tsx for the dashboard page
I think the problem is the action returning a redirect response and the middleware is rewriting
Black carpenter antOP
Ah okay, let me have a try with that and see if it works
@Black carpenter ant Ah okay, let me have a try with that and see if it works
Btw, route group should look like this (auth) and (noAuth)
And I think you dont need to rewrite the response
Black carpenter antOP
Yeah, I was realising that just now, I think I used the wrong terminology, I don't think I'm using route groups for this part of the site
Black carpenter antOP
I'm just deploying now after removing the redirect from the action. In order to redirect from /login to / after the rewrite is changed, should I create a /auth/login/page.tsx that redirects to / so that it gets triggered after the rewrite? I'm struggling to wrap my head around how to properly redirect and rewrite in this instance
Black carpenter antOP
I'm not sure if that would work for what I'm trying to do, I'm trying to have it so that / will change depending on if the user is currently logged in or not, so it'll show a landing screen if logged out and a dashboard if logged in
Ah ok
Does the action and rewriting work without using redirect()?
Black carpenter antOP
It doesn't look like it, no. I've just tried it and the first time calling the action it worked fine and set the cookie but now it's still showing the /noAuth pages but trying to call the server action again results in Failed to find Server Action
@Ray could you show a screenshot of your folder structure?
Black carpenter antOP
@Black carpenter ant Click to see attachment
when visiting "/" it show /dashboard for authenticated user and /landing for unauthenticated?
Black carpenter antOP
That's the plan, it's meant to show /auth/(dashboard)/page.tsx for authed users and /noAuth/page.tsx for unauthed
app/(noAuth)/login/page.tsx
app/(noAuth)/landing/page.tsx
app/(noAuth)/forgot/page.tsx
app/(auth)/dashboard/page.tsx
app/(auth)/logout/page.tsx
app/(auth)/staff/page.tsx

import { NextRequest, NextResponse } from "next/server";

export async function middleware(request: NextRequest) {
  const session = request.cookies.get("kc_session");
  const { pathname, search } = request.nextUrl;

  if (pathname.startsWith("/legal")) {
    return NextResponse.next();
  }

  if (pathname.startsWith("/_next")) {
    return NextResponse.next();
  }

  if (pathname === "/" && session) {
      return NextResponse.rewrite(new URL("/dashboard", request.url));
  }
}
I think this would be alot easier
Black carpenter antOP
I had thought about this but (probably should have shown this before) /dashboard has A LOT more pages
And they go down even further etc.
could you make those sub route under /dashboard?
so you could check the pathname startWith /dashboard in middleware
I think you only need to rewrite on "/"? but you need to protect the route
Or add those route to an array
import { NextRequest, NextResponse } from "next/server";

const protectedRoute = ['/account', '/album', '/artist']

export async function middleware(request: NextRequest) {
  const session = request.cookies.get("kc_session");
  const { pathname, search } = request.nextUrl;

  if (pathname.startsWith("/legal")) {
    return NextResponse.next();
  }

  if (pathname.startsWith("/_next")) {
    return NextResponse.next();
  }

  if (pathname === "/" && session) {
      return NextResponse.rewrite(new URL("/dashboard", request.url));
  }
  if (!session && protectedRoute.include(pathname)) {
    return NextResponse.redirect(new URL("/login", request.url))
  }
}
Black carpenter antOP
I'm just trying one more idea that I had but if it doesn't work then I'll definitely be going with what you've suggested
Black carpenter antOP
I thought it might have been related to route caching, sadly not. I'm going to change it to what you suggested, thank you!