libsql-client-ts icon indicating copy to clipboard operation
libsql-client-ts copied to clipboard

Vercel Turso integration returning 401 for `@libsql/client`

Open petervmeijgaard opened this issue 1 year ago • 4 comments

Description

Hi!

When accessing data from my site hosted on Vercel, I'm getting a 401 HTTP status code being thrown from the @libsql/client and I have no clue why. When I connect to the database locally, I simply cannot reproduce the issue.

I tried recreating the database, recreating the group, and tweaking the Drizzle configuration, but none of it seemed to work. I have no idea what's throwing this exception and why the request from Vercel isn't getting authorized properly.

If more information is necessary, I'd be more than happy to provide this!

Thanks in advance!


More details

Stacktrace
LibsqlError: SERVER_ERROR: Server returned HTTP status 401
    at mapHranaError (file:///var/task/node_modules/.pnpm/@[email protected]/node_modules/@libsql/client/lib-esm/hrana.js:268:16)
    at file:///var/task/node_modules/.pnpm/@[email protected]/node_modules/@libsql/client/lib-esm/http.js:76:23
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async LibSQLPreparedQuery.get (file:///var/task/node_modules/.pnpm/[email protected]_@[email protected]_@[email protected][email protected]_beykhe332nz34cv7xpk57h4rsy/node_modules/drizzle-orm/libsql/session.js:155:18)
    at async login (file:///var/task/build/server/nodejs-eyJydW50aW1lIjoibm9kZWpzIn0/index.js:505:17)
    at async file:///var/task/build/server/nodejs-eyJydW50aW1lIjoibm9kZWpzIn0/index.js:1955:20
    at async Object.callRouteAction (/var/task/node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/data.js:36:16)
    at async /var/task/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/dist/router.cjs.js:4719:19
    at async callLoaderOrAction (/var/task/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/dist/router.cjs.js:4785:16)
    at async Promise.all (index 2) {
  code: 'SERVER_ERROR',
  rawCode: undefined,
  [cause]: HttpServerError: Server returned HTTP status 401
      at errorFromResponse (file:///var/task/node_modules/.pnpm/@[email protected]/node_modules/@libsql/hrana-client/lib-esm/http/stream.js:352:16)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
    status: 401
  }
}
package.json
{
	"name": "[REDACTED]",
	"private": true,
	"sideEffects": false,
	"type": "module",
	"scripts": {
		"build": "remix vite:build",
		"dev": "run-p dev:*",
		"dev:app": "remix vite:dev",
		"dev:turso": "turso dev --db-file './drizzle/db/data.db'",
		"dev:drizzle": "drizzle-kit studio",
		"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
		"start": "remix-serve ./build/server/index.js",
		"db:push": "drizzle-kit push",
		"db:generate": "drizzle-kit generate",
		"db:migrate": "dotenv -e .env -- tsx ./drizzle/migrate.ts",
		"db:seed": "dotenv -e .env -- tsx ./drizzle/seed.ts",
		"db:studio": "drizzle-kit studio",
		"typecheck": "tsc",
		"format": "prettier --check --cache .",
		"prepare": "husky"
	},
	"dependencies": {
		"@conform-to/react": "^1.2.2",
		"@conform-to/zod": "^1.2.2",
		"@epic-web/invariant": "^1.0.0",
		"@epic-web/totp": "^2.0.0",
		"@libsql/client": "^0.14.0",
		"@paralleldrive/cuid2": "^2.2.2",
		"@radix-ui/react-dialog": "^1.1.2",
		"@radix-ui/react-dropdown-menu": "^2.1.2",
		"@radix-ui/react-label": "^2.1.0",
		"@radix-ui/react-popover": "^1.1.2",
		"@radix-ui/react-select": "^2.1.2",
		"@radix-ui/react-separator": "^1.1.0",
		"@radix-ui/react-slot": "^1.1.0",
		"@radix-ui/react-tooltip": "^1.1.3",
		"@react-email/components": "^0.0.25",
		"@remix-run/node": "^2.13.1",
		"@remix-run/react": "^2.13.1",
		"@remix-run/router": "^1.20.0",
		"@remix-run/serve": "^2.13.1",
		"@t3-oss/env-core": "^0.11.1",
		"@vercel/remix": "^2.13.1",
		"bcryptjs": "^2.4.3",
		"class-variance-authority": "^0.7.0",
		"clsx": "^2.1.1",
		"cmdk": "^1.0.0",
		"drizzle-orm": "^0.35.3",
		"input-otp": "^1.2.4",
		"isbot": "^5.1.17",
		"lucide-react": "^0.453.0",
		"react": "rc",
		"react-dom": "rc",
		"remix-themes": "^1.5.1",
		"resend": "^4.0.0",
		"sonner": "^1.5.0",
		"spin-delay": "^2.0.1",
		"tailwind-merge": "^2.5.4",
		"tailwindcss-animate": "^1.0.7",
		"zod": "^3.23.8"
	},
	"devDependencies": {
		"@eslint/js": "^9.13.0",
		"@faker-js/faker": "^9.0.3",
		"@remix-run/dev": "^2.13.1",
		"@total-typescript/tsconfig": "^1.0.4",
		"@types/bcryptjs": "^2.4.6",
		"@types/react": "npm:types-react@rc",
		"@types/react-dom": "npm:types-react-dom@rc",
		"autoprefixer": "^10.4.20",
		"dotenv-cli": "^7.4.2",
		"drizzle-kit": "^0.26.2",
		"eslint": "^9.13.0",
		"eslint-config-prettier": "^9.1.0",
		"eslint-import-resolver-typescript": "^3.6.3",
		"eslint-plugin-import-x": "^4.3.1",
		"eslint-plugin-jsx-a11y": "^6.10.2",
		"eslint-plugin-perfectionist": "^3.9.1",
		"eslint-plugin-react": "^7.37.2",
		"eslint-plugin-react-hooks": "^5.0.0",
		"eslint-plugin-react-refresh": "^0.4.14",
		"globals": "^15.11.0",
		"husky": "^9.1.6",
		"lint-staged": "^15.2.10",
		"npm-run-all": "^4.1.5",
		"postcss": "^8.4.47",
		"prettier": "^3.3.3",
		"prettier-plugin-tailwindcss": "^0.6.8",
		"tailwindcss": "^3.4.14",
		"tsx": "^4.19.1",
		"typescript": "^5.6.3",
		"typescript-eslint": "^8.11.0",
		"vite": "^5.4.10",
		"vite-tsconfig-paths": "^5.0.1"
	},
	"overrides": {
		"@types/react": "npm:types-react@rc",
		"@types/react-dom": "npm:types-react-dom@rc"
	},
	"engines": {
		"node": ">=20.0.0"
	},
	"packageManager": "[email protected]",
	"lint-staged": {
		"*": "prettier --write --ignore-unknown"
	}
}
app/db/index.ts
import { createClient } from "@libsql/client";
import { drizzle } from "drizzle-orm/libsql";

import { env } from "~/lib/env.server";

import * as schema from "./schema";

export const connection = createClient({
	authToken: env.TURSO_AUTH_TOKEN,
	url: env.TURSO_DATABASE_URL,
});

export const db = drizzle(connection, { schema });
app/routes/temp._index/route.tsx
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

import { db } from "~/db";

export async function loader() {
	const users = await db.query.user.findMany();

	return json({ users });
}

export default function Route() {
	const data = useLoaderData<typeof loader>();

	return (
		<div>
			<h1>Users</h1>
			<pre>{JSON.stringify(data, null, 2)}</pre>
		</div>
	);
}
drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
	dbCredentials: {
		authToken: process.env.TURSO_AUTH_TOKEN || undefined,
		// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
		url: process.env.TURSO_DATABASE_URL!,
	},
	dialect: "turso",
	out: "./drizzle/migrations",
	schema: "./app/db/schema.ts",
});

petervmeijgaard avatar Oct 27 '24 14:10 petervmeijgaard

I’ve created a reproduction application which is simply the Remix Vercel template with a Turso Drizzle integration following the steps from the Drizzle documentation

This is giving the same error as mentioned before. What is going on here?

https://github.com/petervmeijgaard/remix-drizzle-vercel

I figured out that this is only involving the serverless environment. The Turso connection is working fine on the edge environment:

petervmeijgaard avatar Oct 28 '24 20:10 petervmeijgaard

I've also faced the same issue, and solved the problem by changing the libsql:// scheme to wss:// scheme. I got the clue from this official turso-drizzle database demo from vercel.

I think it relates to vercel's infrastructure of not handling specific schemes such as libsql://, but I'm not sure since it seems to lack documentation and I didn't dig deep into the problem for right now.

SnowSuno avatar Dec 17 '24 18:12 SnowSuno

I tried the wss:// idea but quickly ran into issues on Vercel in production with HTTP 429 errors.

Internally, it seems using wss:// results in creating a websocket client, which I'm guessing due to the serverless nature of Vercel is not getting disconnected properly, and resulting in an accumulation and maxing out of available connections.

aaroned avatar Jan 19 '25 09:01 aaroned

may this be related?

https://github.com/tursodatabase/libsql/issues/1739

aliozinan avatar Apr 14 '25 11:04 aliozinan