Skip to content

serialize: false on L1 memory seems to incorrectly store serialized string to L2 on refill #111

@denyeo

Description

@denyeo

I think there is a bug in Bentocache 1.5.1 when using:

  • L1 memory driver with serialize: false
  • L2 Redis driver
  • normal JSON-serializable values

This is not about storing non-serializable values like Date, Map, class instances, etc. The cached value here is a plain object.

Config:

import { BentoCache, bentostore } from 'bentocache'
import { memoryDriver } from 'bentocache/drivers/memory'
import { redisDriver } from 'bentocache/drivers/redis'

export const bento = new BentoCache({
  default: 'sessions',
  stores: {
    sessions: bentostore()
      .useL1Layer(memoryDriver({ serialize: false }))
      .useL2Layer(redisDriver({ prefix: 'session:', connection: redisConn })),
  }
})

Cached value is a plain JSON-serializable object:

{
  token: 'xxx',
  uid: 20260004,
  expiresAt: 1776225726287,
  mfa_proofs: [
    {
      authMethodId: 10,
      verifiedAt: 1773633726,
    },
  ],
}

Error I get:

TypeError: Cannot read properties of undefined (reading 'deserialize')
    at _CacheEntry.fromDriver (.../node_modules/bentocache/build/index.js:1047:44)
    at LocalCache.get (.../node_modules/bentocache/build/index.js:1089:30)
    at _Cache.get (.../node_modules/bentocache/build/index.js:492:39)

I got AI to trace it (sorry) and the issue appears to be:

  1. serializeL1 is set to false because the L1 memory driver has serialize: false.
  2. Therefore LocalCache is created with serializer = undefined.
  3. On an L2 hit, Bentocache repopulates L1 like this:
this.#stack.l1?.set(key, remoteItem.entry.serialize(), options);
  1. But remoteItem.entry.serialize() returns a serialized string.
  2. Then the next L1 read does:
const entry = CacheEntry.fromDriver(key, value, this.#serializer);

and CacheEntry.fromDriver does:

if (!serializer && typeof item !== "string") return new _CacheEntry(key, item, serializer);
return new _CacheEntry(key, serializer.deserialize(item) ?? item, serializer);

Now serializer is undefined and item is a string. Then it tries to do:

serializer.deserialize(item)

and crashes.

If serializeL1 === false, Bentocache should not write serialized strings into L1, but it seems to be happening after hitting L2. Then the next L1 read crashes because L1 has no serializer.

AI suggested to ensure the L1 refill path uses the same representation as the original set() path for that cache configuration.

Hope this helps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions