prisma-session-store: `Invalid invocation` error caused by an `update` query

Hello! I’ve been using your module for a bit and I must say it fulfils its mission perfectly.

But sometimes, a random error shows up, and I have no idea why:

set(): Error:
Invalid `this.prisma[this.sessionModelName].update()` invocation in
C:\Users\Maxan\OneDrive\Documents\Code\Mango\node_modules\.pnpm\@quixo3+prisma-session-store@3.1.5_ebc298f2cb1351102aeafce15c5f3d3f\node_modules\@quixo3\prisma-session-store\dist\lib\prisma-session-store.js:486:81

  483 case 3:
  484     _a.trys.push([3, 8, , 9]);
  485     if (!(existingSession !== null)) return [3 /*break*/, 5];
→ 486     return [4 /*yield*/, this.prisma[this.sessionModelName].update(
  Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: ConnectionError(Timed out during query execution.) })

I’m using @quixo3/prisma-session-store@3.1.5 with a SQLite database.

app.use([
    session({
	secret: process.env.SESSION_SECRET,
	cookie: { secure: !process.env.SECURE_COOKIE },
	resave: true,
	saveUninitialized: true,
	store: new PrismaSessionStore(database, { dbRecordIdIsSessionId: true }),
    }),
]);

Do you have an idea of what’s causing it? Thanks a lot!

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 26 (12 by maintainers)

Commits related to this issue

Most upvoted comments

Just posted PR #104, to help fix this issue, at least as a work-around for the moment; and would love to get eyes on it… @msurdi, any chance you might be willing to take a look, and see if there’s anything obviously wrong with it?

I’m using v3.1.9 with prisma v4.3.0 and I was having the same problem.

I found out that if I reloaded my app quickly (CMD+R in the browser), the error was more likely to happen. And tracing back (and by some other explanations on this thread) the culprit seems to be the touch calls that express-session does for every request that goes through the session middleware.

So when my application loaded a view (html), parallel requests are triggered by the browser to download all the CSS/JS assets, and due to the middleware ordering I had a session was being set up even for static assets. This means in a very short amount of time, several concurrent request to my backend were made, all of them trying to touch the session. As far as I understand it (far from expert on this) SQLite has limited support for concurrent write, and I suspect it would be even worse if all those writes are to the same exact record. Here are some nice answers and explanations about this.

So after I inverted the order of the middlewares in my express application (so that first assets are served from express, and later if no asset is served, a session is setup and then my handlers take over) the problem stopped happening.

Given I was still concerned about multiple concurrent requests (by the same user) “touching” the same record in the database in a very limited period of time, I ended up writing my own “Prisma session store” for learning/understanding purposes (which you can find here) and I ended up doing the following workaround so no multiple “touches” happen to the same record concurrently. The specific part of the code that implements this protection is here for reference:

async touch(sid, session, cb) {
    if (this.isTouching[sid]) {
      return cb();
    }
    this.isTouching[sid] = true;
    try {
      await this.db.session.update({
        where: { sid },
        data: { data: JSON.stringify(session) },
      });
    } finally {
      delete this.isTouching[sid];
    }
    return cb();
 }

So, even if probably this is more like a “workaround” than a proper solution, I think for this specific library, one could create a child class of PrismaSessionStore and override the touch method, to include this protection against concurrent touches. I haven’t done this myself as my own minimalistic implementation of this feature seems to be working fine so far (disclaimer: not tested in production, I’m only using it on a side/toy project of mine).

Hope this helps others with this problem 👍

PR #104 merged.

Hi @fowled,

Do you know what is the purpose of that touch function, and at what moment is it called?

I believe that the purpose of touch is primarily to “update” the timestamp - like the way the touch command in unix/linux does for files.

I’m not sure when exactly touch is called though… (It could be that it isn’t called directly within the prisma-session-store library, but that prisma-session-store supplies it in order for express session to be able to call it.

Unfortunately I don’t have much time this week to drill into this… If I did though, I would probably first look through references to touch in express-session: open/closed issues, etc - particularly where expiresAt and/or resave and/or rolling are mentioned. I have a vague (perhaps imagined?) memory that there was a remaining ambiguity about the conditions under which expiresAt is/is not updated - but unfortunately I’m not remembering it here.)

And I can confirm that the expiresAt value updates even with resave: true and rolling: false.

Good to know; hopefully this will help in narrowing down what’s happening / is expected to happen.