withastro/astro

isDbError() does not work

abegehr opened this issue · 5 comments

Astro Info

Astro                    v4.16.10
Node                     v22.6.0
System                   macOS (arm64)
Package Manager          pnpm
Output                   server
Adapter                  @astrojs/vercel/serverless
Integrations             @astrojs/tailwind
                         @astrojs/svelte
                         astro:db
                         @astrojs/db/file-url

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

isDbError(err) is false, even though the error is a LibsqlError SQLITE_CONSTRAINT_UNIQUE thrown from db.insert function in an Astro action.

      try {
        const user = await db.insert(User).values({ name }).returning().get(); // * throws LibsqlError `SQLITE_CONSTRAINT_UNIQUE` when user with name already exists.
        return user;
      } catch (err) {
        if (isDbError(err)) {
          console.warn("LibsqlError thrown:", err); // ! this never get's called, since `isDbError(err)` doesn't seem to work
        } else {
          console.error("Error thrown:", err);
        }
      }

Notice: the StackBlitz repro works only locally, since StackBlitz doesn't support Astro.clientAddress: #6451 (comment)

What's the expected result?

I would expect to be able to identify Libsql errors thrown from inserting into db with astro.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-ofpscu-cwqc8l?file=src%2Factions%2Findex.ts

Participation

  • I am willing to submit a pull request for this issue.

Repo with repro: https://github.com/abegehr/astro-issue-12400-repro (since StackBlitz doesn't support Astro.clientAddress)

To try it out, clone the repro repo, run npm i, and npm run dev. Then click the "Run Action"-button, which will try to insert a user with name=="test" into the database, which will fail uniqueness constraint, since that username is already seeded => Error:

createUser() test
Error thrown: Error: UNIQUE constraint failed: User.name
    at Object.next (/Users/anton/local/repos/astro-issue-12400-repro/node_modules/libsql/index.js:335:20)
    at Statement.all (/Users/anton/local/repos/astro-issue-12400-repro/node_modules/libsql/index.js:360:16)
    at executeStmt (file:///Users/anton/local/repos/astro-issue-12400-repro/node_modules/@libsql/client/lib-esm/sqlite3.js:261:34)
    at Sqlite3Client.execute (file:///Users/anton/local/repos/astro-issue-12400-repro/node_modules/@libsql/client/lib-esm/sqlite3.js:79:16)
    at LibSQLPreparedQuery.values (file:///Users/anton/local/repos/astro-issue-12400-repro/node_modules/drizzle-orm/libsql/session.js:170:59)
    at LibSQLPreparedQuery.get (file:///Users/anton/local/repos/astro-issue-12400-repro/node_modules/drizzle-orm/libsql/session.js:143:29)
    at QueryPromise.get (file:///Users/anton/local/repos/astro-issue-12400-repro/node_modules/drizzle-orm/sqlite-core/query-builders/insert.js:148:28)
    at handler (/Users/anton/local/repos/astro-issue-12400-repro/src/actions/index.ts:15:117)
    at eval (/Users/anton/local/repos/astro-issue-12400-repro/node_modules/astro/dist/actions/runtime/virtual/server.js:68:18)
    at async Module.callSafely (/Users/anton/local/repos/astro-issue-12400-repro/node_modules/astro/dist/actions/runtime/virtual/shared.js:112:18) {
  rawCode: 2067,
  code: 'SQLITE_CONSTRAINT_UNIQUE',
  libsqlError: true
}

However, the catch condition will not identify an LibsqlError with isDbError(). I also tried err instance LibsqlError directly, which also yields false. Therefore doesn't seem to be a way to identify a Libsql/Db-Error.

Screenshot 2024-11-08 at 17 43 03

I've implemented a work-around guard for this:

export function isLibsqlError(err: unknown): err is LibsqlError {
  if (!err || !(err instanceof Error)) return false;
  const value = err as LibsqlError;
  return (
    typeof value.code === "string" &&
    (value.rawCode === undefined || typeof value.rawCode === "number")
  );
}

I can reproduce it locally.

@abegehr would you like to send a PR with your fix?