Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kysely-planetscale causes fetch to fail due to SSL version #25

Closed
jgaltio opened this issue Oct 5, 2023 · 14 comments
Closed

kysely-planetscale causes fetch to fail due to SSL version #25

jgaltio opened this issue Oct 5, 2023 · 14 comments

Comments

@jgaltio
Copy link

jgaltio commented Oct 5, 2023

Using this template: https://github.com/vercel/nextjs-planetscale-nextauth-tailwindcss-template

Fetch fails (this example is from a Canary version of Next.js but I tried numerous versions):

  ▲ Next.js 13.5.5-canary.2
  - Local:        http://localhost:3000
  - Environments: .env.local

 ✓ Ready in 3.7s
 ○ Compiling /page ...
 ✓ Compiled /page in 8.8s (1196 modules)
 ⨯ Internal error: TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11457:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
 ⨯ Internal error: TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11457:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
digest: "2026204822"

It seems the underlying issue is to do with how Kysely handles SSL...

  ] {
    library: 'SSL routines',
    reason: 'wrong version number',
    code: 'ERR_SSL_WRONG_VERSION_NUMBER'
  }

If I use mysql2 instead it works, however I wanted to use your lib like the template intends. Any idea what's going on with this or how to resolve it? It happens both locally and on Vercel.

This is how the library is being used:


import 'server-only';
import { Generated, Kysely } from 'kysely';
import { PlanetScaleDialect } from 'kysely-planetscale';

interface User {
  id: Generated<number>;
  name: string;
  username: string;
  email: string;
}

interface Database {
  users: User;
  // https://github.com/nextauthjs/next-auth/issues/4922
}

export const queryBuilder = new Kysely<Database>({
  dialect: new PlanetScaleDialect({
    url: process.env.DATABASE_URL
  })
});


@jacobwgillespie
Copy link
Member

Hey! I'm not sure what would cause this specifically, likely something about the fetch implementation in your runtime environment or something that Next/Vercel are changing during the build.

It is possible to override the fetch implementation used by @planetscale/database though, see here: https://github.com/planetscale/database-js#custom-fetch-function.

The options passed to new PlanetScaleDialect({...}) are passed to the underlying @planetscale/database instance, so something like:

export const queryBuilder = new Kysely<Database>({
  dialect: new PlanetScaleDialect({
    url: process.env.DATABASE_URL,
    fetch: yourFetchOverride
  })
});

@jgaltio
Copy link
Author

jgaltio commented Oct 9, 2023

Thanks much, Jacob. I gave that a good try with ChatGPT helping me, but even with different fetch providers it still seems to hit the SSL issue.

Is there a way I can / should specify the CA certificate Kysely like

import { Kysely } from 'kysely';
import fs from 'fs';
import path from 'path';

export const db = new Kysely({
  dialect: 'mysql',
  database: process.env.DATABASE_NAME,
  user: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
  host: process.env.DATABASE_HOST,
  port: 3306,
  ssl: {
    ca: fs.readFileSync(path.join(__dirname, 'certs', 'ca.crt')),
    cert: fs.readFileSync(path.join(__dirname, 'certs', 'cacert-2023-08-22.pem'))
  }
});

or

import fs from 'fs';
import path from 'path';
import { Generated, Kysely } from 'kysely';
import { PlanetScaleDialect } from 'kysely-planetscale';

// Only run this code if on the server
const isServer = typeof window === 'undefined';
let sslOptions = {};
if (isServer) {
  sslOptions = {
    ssl: {
      ca: fs.readFileSync(path.join(__dirname, 'certs', 'ca.crt')).toString(),
      cert: fs.readFileSync(path.join(__dirname, 'certs', 'cacert-2023-08-22.pem')).toString(),
      // ... any other required SSL options
    },
  };
}

interface User {
  id: Generated<number>;
  name: string;
  username: string;
  email: string;
}

interface Database {
  users: User;
}

export const queryBuilder = new Kysely<Database>({
  dialect: new PlanetScaleDialect({
    url: process.env.DATABASE_URL,
    ...sslOptions,
  }),
});

or something?

@jacobwgillespie
Copy link
Member

I don't think it's supposed to work like that... one question, you said this is also happening locally: are you using the same DATABASE_URL for both mysql and @planetscale/database? The regular mysql endpoint does not work with PlanetScale's serverless driver, they have a different endpoint for that. I believe it is aws.connect.psdb.cloud for the DATABASE_HOST if your PlanetScale database is hosted in AWS.

@jacobwgillespie
Copy link
Member

Actually I think that's the same endpoint for mysql too, at least for my database - is that the hostname you're using?

@jgaltio
Copy link
Author

jgaltio commented Oct 9, 2023

Yep, mine looks like that and is hosted on AWS. The connection works fine if I'm using Planet Scale CLI or mysql command line. It's just the Next.js implementation that seems... impossible.

As of 2 hours ago I had to finally give up and pivot to a totally different approach but if there's a solution I'm happy to switch back.

@jacobwgillespie
Copy link
Member

@jgaltio One other thing to check, are you specifying a port in your DATABASE_URL? If so, you should not include a port when using @planetscale/database, if you happen to have :3306 in there, that would also cause fetch to fail.

I was able to get that template to work by doing the following:

  1. git clone https://github.com/vercel/nextjs-planetscale-nextauth-tailwindcss-template
  2. Install dependencies with pnpm install
  3. Try to run it with pnpm dev - note it failed here with the fetch failed error
  4. Copied .env.local.example to .env.local and added the database details:
    DATABASE_URL=mysql2://username:[email protected]
    
  5. That worked for me (after creating the database table that the README mentioned)

If it's still broken and you happen to have a repo that reproduces the issue, I'm happy to take a look at that.

@jln13x
Copy link

jln13x commented Oct 16, 2023

Running into the same problem using the local Planetscale CLI.
My Database URL DATABASE_URL=mysql://127.0.0.1/foo

@jacobwgillespie
Copy link
Member

@jln13x that's not a valid database URL for the PlanetScale serverless driver (which uses HTTP rather than the MySQL protocol) - to my knowledge, the local PlanetScale CLI doesn't support the serverless driver like they do the MySQL one. There's an open issue tracking that here: planetscale/database-js#110.

If you want to use Kysely with local MySQL / the PlanetScale CLI, the built-in Kysely MySQL dialect works for that.

@jgaltio
Copy link
Author

jgaltio commented Oct 16, 2023

I thought I had tried with and without the port, but I will confirm. I tried local and remote MySQL but will focus on remote only now.

@tbarn
Copy link

tbarn commented Oct 18, 2023

Hey! +1 to what @jacobwgillespie said. Definitely don't include the port when using database-js. If you try to connect through a default MySQL port like 3306 today, you are going to have issues similar to this. Here's a similar issue in the database-js repo that might help out: planetscale/database-js#142

I would recommend copying it directly from the UI, from Connect modal:
CleanShot 2023-10-18 at 17 15 55@2x

Also, we actually include Kysely specific examples in our new onboarding. We don't reshow it in the UI again right now, but if you go to https://app.planetscale.com/org_name/database_name/connect and select Kysely you can see it.

@mattrobenolt
Copy link

Tangentially related, but if you're interested in experimenting with something I've casually been working on:

https://github.com/mattrobenolt/ps-http-sim

This provides the HTTP shim that you can run locally to pair with a local MySQL database.

@rafalfigura
Copy link

rafalfigura commented Feb 4, 2024

I came across the same problem. I found out that when you directly paste the content of your DATABASE_URL like this:

new Kysely<Database>({ 
  dialect: new PlanetScaleDialect({
    url: 'mysql://o8jh6w53y.....horized":true}',
    format: SqlString.format
  })
});

It works as expected. But when you use process.env.DATABASE_URL it doesn't. Weird.

It looks like the process.env.DATABASE_URL is not available in the edge lambda
console.log({ DATABASE_URL: process.env.DATABASE_URL, url });
logged

{
  DATABASE_URL: undefined,
  url: 'mysql://o8jh6w5...thorized":true}'
}

That's the problem we are facing

@rafalfigura
Copy link

rafalfigura commented Feb 4, 2024

@jacobwgillespie
Copy link
Member

I'm going to close this issue since SSL errors are usually caused either by an incorrect server URL value, or the runtime environment, not this driver directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants