Code Monkey home page Code Monkey logo

next-auth-example-neo4j-adapter-bug's Introduction

Neo4jAdapter Bug Report

To reproduce the bug Neo4jError: You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session, follow these steps.

  1. install deps
npm i
  1. Create a .env.local for a Google (or likely any other) provider:
NEXTAUTH_SECRET=
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
  1. Create a free neo4j db (or use Docker) and then configure the neo4j connection in auth.ts:
const driver = neo4j.driver(
  "neo4j+s://<id>.databases.neo4j.io",
  neo4j.auth.basic("neo4j", "password")
)
  1. Start a dev server with npm run dev, sign in, and then try to visit either http://localhost:3000/server-example or http://localhost:3000/client-example. Both will log the following error:
 โœ“ Compiled /server-example in 279ms (1698 modules)
[auth][error] AdapterError: Read more at https://errors.authjs.dev#adaptererror
[auth][cause]: Neo4jError: You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session.
    at new Neo4jError (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/error.js:74:16)
    at newError (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/error.js:106:12)
    at Session._beginTransaction (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:404:40)
    at eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:531:26)
    at TransactionExecutor.eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:280:37)
    at step (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:117:23)
    at Object.eval [as next] (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:58:20)
    at eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:36:71)
    at new Promise (<anonymous>)
    at __awaiter (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:18:12)
    at TransactionExecutor._executeTransactionInsidePromise (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:268:16)
    at eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:230:19)
    at new Promise (<anonymous>)
    at TransactionExecutor.execute (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:229:16)
    at Session._runTransaction (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:530:42)
    at Session.writeTransaction (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:526:21)
    at write (webpack-internal:///(rsc)/./node_modules/@auth/neo4j-adapter/index.js:293:42)
    at getSessionAndUser (webpack-internal:///(rsc)/./node_modules/@auth/neo4j-adapter/index.js:203:34)
    at acc.<computed> (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/init.js:170:30)
    at Module.session (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/session.js:84:36)
    at AuthInternal (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/index.js:50:77)
    at async Auth (webpack-internal:///(rsc)/./node_modules/@auth/core/index.js:123:29)
    at async UserButton (webpack-internal:///(rsc)/./components/user-button.tsx:19:21)
[auth][details]: {}
[auth][error] SessionTokenError: Read more at https://errors.authjs.dev#sessiontokenerror
[auth][cause]: Neo4jError: You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session.
    at new Neo4jError (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/error.js:74:16)
    at newError (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/error.js:106:12)
    at Session._beginTransaction (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:404:40)
    at eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:531:26)
    at TransactionExecutor.eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:280:37)
    at step (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:117:23)
    at Object.eval [as next] (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:58:20)
    at eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:36:71)
    at new Promise (<anonymous>)
    at __awaiter (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:18:12)
    at TransactionExecutor._executeTransactionInsidePromise (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:268:16)
    at eval (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:230:19)
    at new Promise (<anonymous>)
    at TransactionExecutor.execute (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:229:16)
    at Session._runTransaction (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:530:42)
    at Session.writeTransaction (webpack-internal:///(rsc)/./node_modules/neo4j-driver-core/lib/session.js:526:21)
    at write (webpack-internal:///(rsc)/./node_modules/@auth/neo4j-adapter/index.js:293:42)
    at getSessionAndUser (webpack-internal:///(rsc)/./node_modules/@auth/neo4j-adapter/index.js:203:34)
    at acc.<computed> (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/init.js:170:30)
    at Module.session (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/session.js:84:36)
    at AuthInternal (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/index.js:50:77)
    at async Auth (webpack-internal:///(rsc)/./node_modules/@auth/core/index.js:123:29)
    at async UserButton (webpack-internal:///(rsc)/./components/user-button.tsx:19:21)
[auth][details]: {}

This is related to #5849, but perhaps distinct because it's occurring with @auth/neo4j-adapter and next-auth 5 (beta).

As you can see, const session = await auth() in UserButton is causing the error. This is because const session = await auth() is also called within app/server-example/page.tsx as well as app/client-example/page.tsx. Comment out either of those calls in the pages, so that there's just one const session = await auth() occurring, and the error disappears. Only problem is, I'd like to be able to call const session = await auth() in both UserButton.tsx as well as within my pages. As the error message states, there's an issue with the session lifecycle within the Neo4jAdapter. As the neo4j docs state, "Session creation is a lightweight operation, so sessions can be created and destroyed without significant cost. Always close sessions when you are done with them.".

I suspected the session wasn't being closed and then recreated since the adapter is passed in as Neo4jAdapter(session) instead of as Neo4jAdapter(driver). Looking into node_modules/@auth/neo4j-adapter/index.js, I could see this is the case:

export function Neo4jAdapter(session: Session): Adapter {
  const { read, write } = client(session)
  ...

Above, the session is passed to the client function, which manages the transactions. However, the session never gets closed. Editing the .js code locally, I was able to resolve the error by:

  1. Making the driver the argument to Neo4jAdapter (i.e., export function Neo4jAdapter(session) becomes export function Neo4jAdapter(driver))
  2. Updating auth.ts to pass the driver to Neo4jAdapter:
export const config = {
  theme: {
    logo: "https://next-auth.js.org/img/logo/logo-sm.png",
  },
  adapter: Neo4jAdapter(driver)  // <--- here
  1. Updating the client function to accept the driver instead of a session as its argument. That way we can create new lightweight sessions with each read/write transaction. I also ensured that the read and write functions close the session:
function client(driver) {
    return {
        /** Reads values from the database */
        async read(statement, values) {
            const session = driver.session()
            try {
                const result = await session.executeRead((tx) => tx.run(statement, values));
                return format.from(result?.records[0]?.get(0)) ?? null;
            } finally {
                session.close();  // closing the session
            }
        },
        /**
         * Reads/writes values from/to the database.
         * Properties are available under `$data`
         */
        async write(statement, values) {
            const session = driver.session()
            try {
                const result = await session.executeWrite((tx) => tx.run(statement, { data: format.to(values) }));
                return format.from(result?.records[0]?.toObject());
            } finally {
                session.close();  // closing the session
            }
        },
    };
}
  1. Scope down instantiation of the read/write functions within Neo4jAdapter, e.g.,
export function Neo4jAdapter(driver) {
    // const { read, write } = client(session)  // move this down
    return {
        async createUser(data) {
            const { write } = client(driver)  // scope client (and session) instantiation to each adapter method
            const user = { ...data, id: crypto.randomUUID() };
            await write(`CREATE (u:User $data)`, user);
            return user;
        },
        async getUser(id) {
            const { read } = client(driver) // scope client (and session) instantiation to each adapter method
            return await read(`MATCH (u:User { id: $id }) RETURN u{.*}`, {
                id,
            });
        },
        ...

After doing the above and performing a rm -rf .next, the error message goes away and the demo app runs swimmingly.

next-auth-example-neo4j-adapter-bug's People

Contributors

balazsorban44 avatar iaincollins avatar ndom91 avatar dependabot[bot] avatar csmcallister avatar amortka avatar alex-marinov avatar apyrkh avatar anthonyringoet avatar heyanurag avatar braydentw avatar bmuenzenmeyer avatar danielvandenberg95 avatar dferber90 avatar enbonnet avatar fathymuhamed avatar gianpaj avatar cg2p avatar ubbe-xyz avatar mahieyin-rahmun avatar mcsdevv avatar sgmiguel avatar schoenwaldnils avatar suyalcinkaya avatar sushritpasupuleti avatar yeabu369 avatar juke-coder avatar kostazol avatar jeffersonbledsoe avatar tst-fractal avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.