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

Vercel Turso integration returning 401 for @libsql/client #280

Open
petervmeijgaard opened this issue Oct 27, 2024 · 3 comments
Open

Vercel Turso integration returning 401 for @libsql/client #280

petervmeijgaard opened this issue Oct 27, 2024 · 3 comments

Comments

@petervmeijgaard
Copy link

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
Copy link
Author

petervmeijgaard commented Oct 28, 2024

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:

@SnowSuno
Copy link

SnowSuno commented Dec 17, 2024

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.

@aaroned
Copy link

aaroned commented Jan 19, 2025

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.

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

3 participants