Summary
RedisDriver and redisBusDriver decide whether config.connection is an existing client via instanceof IoRedis || instanceof IoRedisCluster (redis.ts#L38, #L63). That check uses bentocache's own ioredis copy. When the host app resolves a different ioredis major, the check is false for a perfectly valid client and the driver silently does new IoRedis(connection) with a Redis instance as the options object. ioredis ignores the unknown shape and connects to 127.0.0.1:6379.
This just happened via @adonisjs/cache@2.1.0 (passes redis.connection(name).ioConnection) after @adonisjs/redis@10.0.1 bumped ioredis to ^6.0.0 while bentocache still peers on ^5.3.2. pnpm installs both 5.11.1 and 6.0.0, and production ended up with:
[ioredis] Unhandled error event: Error: connect ECONNREFUSED 127.0.0.1:6379
repeated every ~2s indefinitely (ioredis 5 default retry, since the app's retryStrategy never reached the stray client).
Suggestions
- Duck-type instead of
instanceof: e.g. typeof connection.duplicate === 'function' && typeof connection.sendCommand === 'function' (or check for status/options), so any ioredis major works when handed an instance.
- Widen the peer range to
^5.3.2 || ^6.0.0 once verified against RESP3 defaults.
- At minimum, throw when
config.connection looks like a client but fails the instanceof check, instead of falling back to localhost. A loud failure would have made this a 5 minute diagnosis rather than a production incident.
Same pattern exists in @boringnode/bus RedisTransport (options instanceof Redis), though @adonisjs/cache passes plain options to the bus so that path was not hit here.
Related upstream report on adonisjs/redis: adonisjs/redis#77
Env
bentocache 1.6.1, @adonisjs/cache 2.1.0, @adonisjs/redis 10.0.1 (ioredis 6.0.0) alongside bentocache's ioredis 5.11.1
- pnpm 10, Node 24
Summary
RedisDriverandredisBusDriverdecide whetherconfig.connectionis an existing client viainstanceof IoRedis || instanceof IoRedisCluster(redis.ts#L38, #L63). That check uses bentocache's owniorediscopy. When the host app resolves a different ioredis major, the check isfalsefor a perfectly valid client and the driver silently doesnew IoRedis(connection)with a Redis instance as the options object. ioredis ignores the unknown shape and connects to127.0.0.1:6379.This just happened via
@adonisjs/cache@2.1.0(passesredis.connection(name).ioConnection) after@adonisjs/redis@10.0.1bumpedioredisto^6.0.0while bentocache still peers on^5.3.2. pnpm installs both5.11.1and6.0.0, and production ended up with:repeated every ~2s indefinitely (ioredis 5 default retry, since the app's
retryStrategynever reached the stray client).Suggestions
instanceof: e.g.typeof connection.duplicate === 'function' && typeof connection.sendCommand === 'function'(or check forstatus/options), so any ioredis major works when handed an instance.^5.3.2 || ^6.0.0once verified against RESP3 defaults.config.connectionlooks like a client but fails theinstanceofcheck, instead of falling back to localhost. A loud failure would have made this a 5 minute diagnosis rather than a production incident.Same pattern exists in
@boringnode/busRedisTransport(options instanceof Redis), though@adonisjs/cachepasses plain options to the bus so that path was not hit here.Related upstream report on adonisjs/redis: adonisjs/redis#77
Env
bentocache1.6.1,@adonisjs/cache2.1.0,@adonisjs/redis10.0.1 (ioredis 6.0.0) alongside bentocache's ioredis 5.11.1