redis/node-redis

TypeError when "DENIED Redis is running in protected mode ..."

JohnnyRacer opened this issue ยท 16 comments

Description

I am getting a very strange type error everytime I try to use docker compose up to launch any script that connects to redis with the following error message:

redis-test /node_modules/@redis/client/dist/lib/client/commands-queue.js:62
redis-test                 const { resolve, reject } = __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").shift();
redis-test                         ^
redis-test 
redis-test TypeError: Cannot destructure property 'resolve' of '__classPrivateFieldGet(...).shift(...)' as it is undefined.
redis-test     at Object.onReply (/node_modules/@redis/client/dist/lib/client/commands-queue.js:62:25)
redis-test     at RESP2Decoder.write (/node_modules/@redis/client/dist/lib/client/RESP2/decoder.js:119:26)
redis-test     at RedisCommandsQueue.onReplyChunk (/node_modules/@redis/client/dist/lib/client/commands-queue.js:154:72)
redis-test     at RedisSocket.<anonymous> (/node_modules/@redis/client/dist/lib/client/index.js:388:84)
redis-test     at RedisSocket.emit (node:events:512:28)
redis-test     at Socket.<anonymous> (/node_modules/@redis/client/dist/lib/client/socket.js:202:42)
redis-test     at Socket.emit (node:events:512:28)
redis-test     at addChunk (node:internal/streams/readable:324:12)
redis-test     at readableAddChunk (node:internal/streams/readable:297:9)
redis-test     at Readable.push (node:internal/streams/readable:234:10)
redis-test 
redis-test Node.js v19.6.1
redis-test exited with code 1

This error does not happen when I connect to redis using the node.js REPL without docker.

This is the docker-compose.yml file I am using to create the redis container:

  redis:
    image: redis/redis-stack:latest
    ports:
      - 6379:6379
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis-data:/data

And the code I am using in node.js to connect to redis

import { createClient } from "redis";
(async function () {
    const rdb = createClient({
        url: 'redis://redis:6379'
        });
   
    await rdb.connect();
})();

Node.js Version

19.6.1

Redis Server Version

6.2.8

Node Redis Version

4.6.4

Platform

Linux

Logs

No response

@JohnnyRacer as far as I can tell, this error means that the client got a reply from redis-server, but there are no commands in the queue, which is indeed very strange.

  1. Are you using the client? executing any commands?
  2. Does the error throws immediately?
  3. Can you please add console.log(reply); before node_modules/@redis/client/dist/lib/client/commands-queue.js:62?

If you want, I'll be happy to debug it with you, let me know.. :)

@JohnnyRacer as far as I can tell, this error means that the client got a reply from redis-server, but there are no commands in the queue, which is indeed very strange.

1. Are you using the client? executing any commands?

2. Does the error throws immediately?

3. Can you please add `console.log(reply);` before `node_modules/@redis/client/dist/lib/client/commands-queue.js:62`?

If you want, I'll be happy to debug it with you, let me know.. :)

@leibale

  1. This error occurs before any commands are sent to the client, this happens whenever await client.connect() is called.
  2. Yes.
  3. With console.log(reply) before node_modules/@redis/client/dist/lib/client/commands-queue.js:62.
[ErrorReply: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.]

@leibale

Seems like node-redis does not throw a clear exception when --protected-mode no and a password is not set, I just set this flag in my docker-compose.yml file and now it connects fine with no errors. Not sure if this has any implications for security in production though since I am only accessing redis from my local network, but for testing/development it works fine.

@JohnnyRacer thanks for the information, I'll investigate that. Glad you found a workaround :)

@leibale I ran into this issue as well. The Redis server will send -DENIED or -ERR in some circumstances unconditionally and close the connection: See acceptCommonHandler() in https://github.com/redis/redis/blob/e7a3d3d152c251cc25aed3d89a47a525812e72de/src/networking.c#L1283

I think the library should be able to handle this.

@dtikhonov-iex the library should be able to handle these errors, that's why the issue is still open.. :)

I have found another instance of this happening when using legacyMode: true:

When using pub/subs in legacy mode, be sure to use the v4 functions.

In legacyMode, this will throw the same error as OP.

const heartbeat = redis_client.duplicate();
heartbeat.on('error', err => handleError(err));
heartbeat.connect()
.then(() => {
    const listener = (incoming) => {
        doListenerThings(incoming)
    }
    heartbeat.subscribe('key:key:key', listener);
})
.catch(err => handleError(err))

This works fine.

const heartbeat = redis_client.duplicate();
heartbeat.on('error', err => handleError(err));
heartbeat.connect()
.then(() => {
    const listener = (incoming) => {
        doListenerThings(incoming)
    }
    //THIS IS THE DIFFERENCE
    heartbeat.v4.subscribe('key:key:key', listener);
})
.catch(err => handleError(err))

Adding this here incase more information is wanted:

Running this using the latest version of node 18 seems to resolve the issue, where as the latest LTS seems to cause issue. Recently migrated a program using this package to node 20 and we started finding this issue everytime we tried to start it. After reverting it back to node 18, it was fine again.

Also using redis-stack-server in a docker container

Hi, same issue with nodejs version 18.17.1

TypeError: Cannot destructure property 'resolve' of '__classPrivateFieldGet(...).shift(...)' as it is undefined.
    at Object.onReply (/opt/def/def-puresocial-services/node_modules/@redis/client/dist/lib/client/commands-queue.js:62:25)
    at RESP2Decoder.write (/opt/def/def-puresocial-services/node_modules/@redis/client/dist/lib/client/RESP2/decoder.js:119:26)
    at RedisCommandsQueue.onReplyChunk (/opt/def/def-puresocial-services/node_modules/@redis/client/dist/lib/client/commands-queue.js:154:72)
    at RedisSocket.<anonymous> (/opt/def/def-puresocial-services/node_modules/@redis/client/dist/lib/client/index.js:394:84)
    at RedisSocket.emit (node:events:514:28)
    at Socket.<anonymous> (/opt/def/def-puresocial-services/node_modules/@redis/client/dist/lib/client/socket.js:201:42)
    at Socket.emit (node:events:514:28)
    at addChunk (node:internal/streams/readable:324:12)
    at readableAddChunk (node:internal/streams/readable:297:9)
    at Readable.push (node:internal/streams/readable:234:10)

Node.js v18.17.1

Version of redis package is 4.6.10

i got this problem. then i found this only happens when connect to remote redis.

i try redis-cli, got (error) DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients.

so this problem may not be this package's issue, but it is still makes people confuse.

node 18.15.0, "cache-manager-redis-store": "^3.0.1", It happens when using remote redis while local development. After a couple of minutes this error appears:
`/Users/user/WebstormProjects/monolytics/node_modules/@redis/client/dist/lib/client/socket.js:194
__classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_onSocketError).call(this, new errors_1.SocketClosedUnexpectedlyError());
^

Error: Socket closed unexpectedly
at TLSSocket. (/Users/user/WebstormProjects/monolytics/node_modules/@redis/client/dist/lib/client/socket.js:194:118)
at Object.onceWrapper (node:events:628:26)
at TLSSocket.emit (node:events:525:35)
at TLSSocket.emit (node:domain:489:12)
at node:net:322:12
at TCP.done (node:_tls_wrap:588:7)`

I have found another instance of this happening when using legacyMode: true:

When using pub/subs in legacy mode, be sure to use the v4 functions.

In legacyMode, this will throw the same error as OP.

const heartbeat = redis_client.duplicate();
heartbeat.on('error', err => handleError(err));
heartbeat.connect()
.then(() => {
    const listener = (incoming) => {
        doListenerThings(incoming)
    }
    heartbeat.subscribe('key:key:key', listener);
})
.catch(err => handleError(err))

This works fine.

const heartbeat = redis_client.duplicate();
heartbeat.on('error', err => handleError(err));
heartbeat.connect()
.then(() => {
    const listener = (incoming) => {
        doListenerThings(incoming)
    }
    //THIS IS THE DIFFERENCE
    heartbeat.v4.subscribe('key:key:key', listener);
})
.catch(err => handleError(err))

Thanks for your response, ๐Ÿ™Œ it's work for me โค๏ธ

I have the same issue, using it as described on the socket.io Redis adapter page.
I use the import { createAdapter } from '@socket.io/redis-adapter',

This occurs in my case when the client is waiting for the server to start up for the first time. As the queue returns undefined because there is nothing on the queue yet.

Hacking in a solution into the transpiled javascript code, I've come to the following fix.
In @redis/client/dist/lib/client/commands-queue.js of my node modules directory.

I replace

const { resolve, reject } = __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").shift()

with

const { resolve, reject } = __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").shift() || {resolve:()=>{}, reject:()=>{}};

and this solves my issue.

Again this is a hack. The real issue stems from the non-null assertion operator found here in the source code.

const { resolve, reject } = this.#waitingForReply.shift()!;

UPDATE

Looks like this PR has a fix for the issue #2549

Had to hack this also. Would be great to have lib support.

Redis Reinstallation Process

  1. Remove the Existing Redis Installation
    Run the following command to completely remove Redis along with its dependencies:
   sudo apt-get purge --auto-remove redis-server redis
  1. Terminate All Redis Processes
    Use the command below to list and kill all Redis processes:
   ps aux | grep redis
  1. Configure the Bind Address
    Edit the Redis configuration file to specify the IP addresses you want Redis to listen on:
   sudo nano /etc/redis/redis.conf

Add the following lines, replacing 127.0.0.1 and 0.0.0.0 with your actual IP addresses:

   bind 127.0.0.1
   bind 0.0.0.0
  1. Install Redis Tools
    To install additional Redis tools, run:
   sudo apt install redis-tools
  1. Restart the Redis Service
    Finally, restart the Redis service to apply the changes:
   sudo systemctl restart redis

This should help clarify the steps involved in the Redis reinstallation process!