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

Neo4j session error (GetSessionAndUserError) #5849

Open
vladutilie opened this issue Nov 18, 2022 · 18 comments
Open

Neo4j session error (GetSessionAndUserError) #5849

vladutilie opened this issue Nov 18, 2022 · 18 comments
Labels
adapters Changes related to the core code concerning database adapters neo4j @auth/neo4j-adapter triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@vladutilie
Copy link

vladutilie commented Nov 18, 2022

Adapter type

@next-auth/neo4j-adapter

Environment

System:
OS: macOS 13.0
CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 317.06 MB / 16.00 GB
Shell: 3.2.57 - /bin/bash

Binaries:
Node: 18.12.1 - /usr/local/opt/node@18/bin/node
Yarn: 1.22.11 - /usr/local/bin/yarn
npm: 8.19.2 - /usr/local/opt/node@18/bin/npm

Browsers:
Chrome: 107.0.5304.110
Firefox: 101.0
Safari: 16.1

npmPackages:
next: 13.0.4 => 13.0.4
next-auth: ^4.16.4 => 4.16.4
react: 18.2.0 => 18.2.0
neo4j-driver: ^5.2.0
swr: ^1.3.0
typescript: 4.9.3

npmPackages:
@next-auth/neo4j-adapter: ^1.0.5 => 1.0.5

Reproduction URL

https://github.com/vladutilie/issue-next-auth-neo4j

Describe the issue

Hello,

Vlad here, a Next.js and awesome-packages-related fan, enthusiast 😎 and hopefully a contributor to this community.

Since I've started to use Neo4j as Adapter for my NextAuth implementation, I got this error in logs and the client cannot get API responses if the focus of the page is lost. I'm using SWR to call an API endpoint which is using the unstable_getServerSession function to check if the user is authenticated.

Long story short

🍀 I start the server, I open the page (let's say I'm authenticated) and all data from my API (fetched with SWR) is in place. I browse my page and so on, and all is perfect.

🍎 The issue occurs when I click on another tab (or just I open a new one), browse there for some seconds, and then come back to my initial tab - this will trigger SWR to revalidate (re-fetch) the date. The SWR fetch fails because the unstable_getServerSession function returns null 🤷🏻‍♂️ and at the same time I get the following error.

The error I got

The error I got in VS code logs is the following:

[next-auth][error][adapter_error_getSessionAndUser] 
https://next-auth.js.org/errors#adapter_error_getsessionanduser You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session. {
  message: 'You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session.',
  stack: 'Neo4jError: You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session.\n' +
    '    at new Neo4jError (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:77:16)\n' +
    '    at newError (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:113:12)\n' +
    '    at Session._beginTransaction (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:280:40)\n' +
    '    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:394:77\n' +
    '    at TransactionExecutor.<anonymous> (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:116:46)\n' +
    '    at step (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:52:23)\n' +
    '    at Object.next (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:33:53)\n' +
    '    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:27:71\n' +
    '    at new Promise (<anonymous>)\n' +
    '    at __awaiter (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:23:12)',
  name: 'Neo4jError'
}
[next-auth][error][SESSION_ERROR] 
https://next-auth.js.org/errors#session_error You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session. 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 (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:77:16)
    at newError (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:113:12)
    at Session._beginTransaction (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:280:40)
    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:394:77
    at TransactionExecutor.<anonymous> (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:116:46)
    at step (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:52:23)
    at Object.next (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:33:53)
    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:27:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:23:12) {
  name: 'GetSessionAndUserError',
  code: 'N/A'
}

What I have tried?

I have tried to call session.close() in node_modules/@next-auth/neo4j-adapter/dist/utils.js like below, hoping for an eventually fix, but it was in vain:

function client(session) {
    return {
        /** Reads values from the database */
        async read(statement, values) {
            var _a, _b;
            const result = await session.readTransaction((tx) => tx.run(statement, values));
            session.close(); // 👈
            return (_b = exports.format.from((_a = result === null || result === void 0 ? void 0 : result.records[0]) === null || _a === void 0 ? void 0 : _a.get(0))) !== null && _b !== void 0 ? _b : null;
        },
        /**
         * Reads/writes values from/to the database.
         * Properties are available under `$data`
         */
        async write(statement, values) {
            var _a;
            const result = await session.writeTransaction((tx) => tx.run(statement, { data: exports.format.to(values) }));
            session.close(); // 👈
            return exports.format.from((_a = result === null || result === void 0 ? void 0 : result.records[0]) === null || _a === void 0 ? void 0 : _a.toObject());
        },
    };
}

The error I got after my try

Cannot begin a transaction on a closed session. 🤦‍♂️

[next-auth][error][adapter_error_getSessionAndUser] 
https://next-auth.js.org/errors#adapter_error_getsessionanduser Cannot begin a transaction on a closed session. {
  message: 'Cannot begin a transaction on a closed session.',
  stack: 'Neo4jError: Cannot begin a transaction on a closed session.\n' +
    '    at new Neo4jError (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:77:16)\n' +
    '    at newError (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:113:12)\n' +
    '    at Session._beginTransaction (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:277:40)\n' +
    '    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:394:77\n' +
    '    at TransactionExecutor.<anonymous> (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:116:46)\n' +
    '    at step (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:52:23)\n' +
    '    at Object.next (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:33:53)\n' +
    '    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:27:71\n' +
    '    at new Promise (<anonymous>)\n' +
    '    at __awaiter (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:23:12)',
  name: 'Neo4jError'
}
[next-auth][error][SESSION_ERROR] 
https://next-auth.js.org/errors#session_error Cannot begin a transaction on a closed session. Neo4jError: Cannot begin a transaction on a closed session.
    at new Neo4jError (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:77:16)
    at newError (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/error.js:113:12)
    at Session._beginTransaction (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:277:40)
    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/session.js:394:77
    at TransactionExecutor.<anonymous> (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:116:46)
    at step (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:52:23)
    at Object.next (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:33:53)
    at /Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:27:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/vlad/www/issue-next-auth-neo4j/node_modules/neo4j-driver-core/lib/internal/transaction-executor.js:23:12) {
  name: 'GetSessionAndUserError',
  code: 'N/A'
}

So I came here for another perspective. 🎩
Of course, I'm willing to help, just let me know how 😇.

How to reproduce

  1. Clone the repository: https://github.com/vladutilie/issue-next-auth-neo4j
  2. Run $ yarn install
  3. Run $ cp .env.example .env
  4. Set up the fields in .env file (you will need a Neo4j database instance - I'm using Neo4j Desktop for local development but you can use an AuraDB or something similar as well)
  5. Run $ npm run dev in terminal
  6. Open the link http://localhost:3000/api/auth/signin in Chrome or Firefox, put your email and authenticate yourself
  7. You will see a text like this on the page: {"user":{"email":"you@email.com"},"expires":"2022-12-18T20:12:48.651Z"}
  8. Open a new tab in the browser and access a random page - this will trigger losing focus of the current page and will make SWR revalidate (re-fetch) the data from the API (/api/hello endpoint in this case)
  9. Click back on the initial tab after a few seconds
  10. You will see the text {"message":"Not authenticated."} in the page
  11. Go into your logs and you will see the error described above.

Expected behavior

After the 9th step from reproduction, on the page you should see the same text you saw first, something like {"user":{"email":"you@email.com"},"expires":"2022-12-18T20:12:48.651Z"} and the logs should not have that error, so the unstable_getServerSession function should return the authenticated user data.

@vladutilie vladutilie added adapters Changes related to the core code concerning database adapters triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Nov 18, 2022
@github-actions github-actions bot added the neo4j @auth/neo4j-adapter label Nov 18, 2022
@EarthlingDavey
Copy link

EarthlingDavey commented Dec 12, 2022

Hi @vladutilie could you try with neo4j-driver 4.x ?

It seems 5 was only rolled out a few months ago and the neo4j adapret is tested up to version 4.

This way at least we will know how to proceeed, additional tests/amends for v5 or futher investigation elsewhere.

@vladutilie
Copy link
Author

Hi @EarthlingDavey! Thank you for taking the time to respond to me.

I have tried both 4.4.10 (the last version 4) and 4.3.1 (the one which is in the with-neo4j example) and unfortunately, I got the same error.

Thank you!

@EarthlingDavey
Copy link

EarthlingDavey commented Dec 13, 2022

Hey @vladutilie sorry i can't dedicate a bunch of time to help but I can give some pointers.

  • This error is related to a neo4j session. I've seen it often before and it can most easilly be replicated by starting a neo4j session from the driver. Then closing with session.close() then attempting to read or write from the database with the closed session.
  • Edit: I've re-read the error message, it's caused by running 2 or more simultanious database transactions with a single database session. Currently the adapter uses a single session for all database actions.
  • You could verify the session on this line with logging or a breakpoint. I think there is an isConnected() method or similar.
  • In the options set debug: true . You may get some more useful info.
  • Also, I don't know how often a new driver / session is created in the neo4j example. I have the following code in a sepetate file so that the driver is created once per nodejs process
// neo4j.js
import neo4j from 'neo4j-driver';
let driver;
export default function getDriver() {
  if (!driver) {
    driver = neo4j.driver(url, neo4j.auth.basic(username, password), options);
  }
  return driver;
}

I have this adapter runing in production with pinned slightly old versions and jwt (not using unstable_getServerSession).

I suspect the error you're seeing is because of some new feature or change (to this package or other dependancy) since the neo4j adapter was written.

Sorry I can't assingn myself to fix this right now, my work load is huge.
Regardless, let me know how you get on.

@pedsm

This comment was marked as spam.

@Ka0shi

This comment was marked as off-topic.

@Konzti

This comment was marked as off-topic.

@indicozy

This comment was marked as spam.

@reedling78

This comment was marked as spam.

@EarthlingDavey
Copy link

@balazsorban44 @ndom91 Hi, I need some advice on my approaach to fix this, please.

It looks 2 (or more) adapter functions are running at the same time. Looking at the bug report I think getSessionAndUser is being run while still in the middle of a current adapter function.

I've checked (the neo4j adapter)[https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-neo4j/src/index.ts] and all functions are async and have the correct await.

I think that unstable_getServerSession or some other part of core next-auth is not awaiting the return value of adapter functions. Hence allowing 2 to be run at the same time, causing the error.

I can see 2 approaches to a fix:

  • Ensure core always awaits the adapter function return value.
  • Change the neo4j adapter so that a new session is created for each transaction. To keep backward compatibility - this could be done by optionally passing the neo4j-driver as an adapter parameter.

Do you think my diagnosis is right? I can implement the neo4j-adapter change, plase advise.

@EarthlingDavey
Copy link

EarthlingDavey commented Feb 25, 2023

Yes, it's related to this.

But a correction is that:

  • it's ok to use a session for many database transactions,
  • but it will throw an error if a session attempts multiple transactions at the same time.

Taking the example from The session API docs

const session = driver.session()
const titles = []
try {
  // This will work note the await
  const result1 = await session.executeRead(tx =>
    tx.run('MATCH (p:Product) WHERE p.id = $id RETURN p.title', { id: 0 })
  )
  const result2 = await session.executeRead(tx =>
    tx.run('MATCH (p:Product) WHERE p.id = $id RETURN p.title', { id: 0 })
  )

  // This might error because of not awaiting for a tx to complete before starting the next one.
  const resultPromise3 = session.executeRead(tx =>
    tx.run('MATCH (p:Product) WHERE p.id = $id RETURN p.title', { id: 0 })
  )
  const resultPromise4 = session.executeRead(tx =>
    tx.run('MATCH (p:Product) WHERE p.id = $id RETURN p.title', { id: 0 })
  )

  const [result3, result4] = await Promise.all([resultPromise3, resultPromise4])
  
} finally {
  await session.close()
}

@indicozy
Copy link

@EarthlingDavey Are you writing about the comment that I deleted?

@EarthlingDavey
Copy link

@indicozy yes, maybe you already knew, but I posted an example anyways.

@indicozy
Copy link

indicozy commented Feb 25, 2023

FYI this error does not pop up on Vercel functions, so it verifies the hypothesis

@w-dib

This comment was marked as off-topic.

@EarthlingDavey
Copy link

Hi @w-dib thanks for your comment. But I'm almost certain that although you're seeing a similar/same error message - your issue is unrelated.

The issue here is that next-auth is trying to do 2 simultanious database writes and the neo4j adapter was not written with this use case in mind.

You should search through existing issues to see if one does exactly mach with yours. Else, please create a new issue, following the template :)

@DharmPatel4300

This comment was marked as off-topic.

@Reddsito

This comment was marked as off-topic.

@EarthlingDavey
Copy link

Hi @Reddsito. If you're using Prisma, you should search existing tickets. If no existing ticket matches your issue then create a new one. This issue is about neo4j, not Prisma.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
adapters Changes related to the core code concerning database adapters neo4j @auth/neo4j-adapter triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests

10 participants