Skip to content

Troubleshooting

Common issues and how to fix them.

Connection Issues

Cannot Connect to Redis

Symptoms:

  • ECONNREFUSED error
  • Timeout on connection
  • Application hangs on startup

Solutions:

  1. Check Redis is running:
bash
redis-cli ping
# Should return: PONG
  1. Verify host and port:
typescript
RedisModule.forRoot({
  clients: {
    host: 'localhost',  // Correct host?
    port: 6379,         // Correct port?
  },
})
  1. Check network access:
bash
# Test connectivity
telnet localhost 6379

# Or with nc
nc -zv localhost 6379
  1. Docker networking:
typescript
// Inside Docker, use service name
RedisModule.forRoot({
  clients: {
    host: 'redis',  // Docker service name
    port: 6379,
  },
})

Authentication Failed

Symptoms:

  • NOAUTH Authentication required
  • ERR invalid password

Solutions:

typescript
RedisModule.forRoot({
  clients: {
    host: 'localhost',
    port: 6379,
    password: process.env.REDIS_PASSWORD,  // Add password
  },
})

TLS Connection Failed

Symptoms:

  • UNABLE_TO_VERIFY_LEAF_SIGNATURE
  • SELF_SIGNED_CERT_IN_CHAIN
  • Connection timeout with TLS

Solutions:

typescript
RedisModule.forRoot({
  clients: {
    host: 'redis.example.com',
    port: 6380,
    tls: {
      enabled: true,
      rejectUnauthorized: false,  // Development only!
    },
  },
})

// Production with proper certificates
RedisModule.forRoot({
  clients: {
    host: 'redis.example.com',
    port: 6380,
    tls: {
      enabled: true,
      ca: fs.readFileSync('/path/to/ca.crt'),
      cert: fs.readFileSync('/path/to/client.crt'),
      key: fs.readFileSync('/path/to/client.key'),
    },
  },
})

Module Configuration Issues

Client Not Found

Symptoms:

  • Client "xyz" not found
  • Available clients: default

Solutions:

  1. Check client name matches:
typescript
// Configuration
RedisModule.forRoot({
  clients: {
    cache: { host: 'localhost', port: 6379 },  // Named 'cache'
  },
})

// Usage — via RedisService
const client = await this.redis.getClient('cache');  // Must match

// Usage — via @InjectRedis decorator
@Injectable()
export class MyService {
  constructor(
    @InjectRedis('cache') private readonly cacheDriver: IRedisDriver,
  ) {}
}
  1. Verify multiple clients configured:
typescript
RedisModule.forRoot({
  clients: {
    default: { host: 'localhost', port: 6379 },
    cache: { host: 'cache-server', port: 6379 },
    sessions: { host: 'session-server', port: 6379 },
  },
})
  1. Using @InjectRedis with wrong name:
typescript
// ❌ Name doesn't match any configured client
@InjectRedis('redis-cache')  // No client named 'redis-cache'

// ✅ Use exact name from configuration
@InjectRedis('cache')  // Matches 'cache' key in clients
@InjectRedis()          // Uses 'default' client

Module Not Initialized

Symptoms:

  • Cannot read property 'getClient' of undefined
  • RedisService is not defined

Solutions:

  1. Ensure module is imported:
typescript
@Module({
  imports: [
    RedisModule.forRoot({
      clients: { host: 'localhost', port: 6379 },
    }),
  ],
})
export class AppModule {}
  1. Check async configuration:
typescript
RedisModule.forRootAsync({
  imports: [ConfigModule],  // Import dependencies
  useFactory: (config: ConfigService) => ({
    clients: {
      host: config.get('REDIS_HOST'),
      port: config.get('REDIS_PORT'),
    },
  }),
  inject: [ConfigService],  // Inject dependencies
})

Circular Dependency

Symptoms:

  • Nest cannot resolve dependencies
  • A circular dependency has been detected

Solutions:

typescript
// Use forwardRef for circular dependencies
@Injectable()
export class ServiceA {
  constructor(
    @Inject(forwardRef(() => ServiceB))
    private readonly serviceB: ServiceB,
    private readonly redis: RedisService,
  ) {}
}

Cluster Issues

MOVED/ASK Redirections

Symptoms:

  • MOVED 12345 192.168.1.2:6379
  • ASK 12345 192.168.1.2:6379

Solutions:

typescript
// Increase max redirections
RedisModule.forRoot({
  clients: {
    type: 'cluster',
    nodes: [...],
    clusterOptions: {
      maxRedirections: 32,  // Increase from default 16
    },
  },
})

Cluster Down

Symptoms:

  • CLUSTERDOWN The cluster is down
  • Operations fail intermittently

Solutions:

typescript
// Configure retry delays
RedisModule.forRoot({
  clients: {
    type: 'cluster',
    nodes: [...],
    clusterOptions: {
      retryDelayOnClusterDown: 300,  // Wait longer
      retryDelayOnFailover: 200,
    },
  },
})

NAT/Docker Issues

Symptoms:

  • Works initially, then fails
  • MOVED to internal IP addresses

Solutions:

typescript
// Use NAT mapping
RedisModule.forRoot({
  clients: {
    type: 'cluster',
    nodes: [
      { host: 'localhost', port: 7000 },
    ],
    clusterOptions: {
      natMap: {
        '172.17.0.2:6379': { host: 'localhost', port: 7000 },
        '172.17.0.3:6379': { host: 'localhost', port: 7001 },
        '172.17.0.4:6379': { host: 'localhost', port: 7002 },
      },
    },
  },
})

Sentinel Issues

Cannot Find Master

Symptoms:

  • Master not found
  • Connection to sentinel failed

Solutions:

typescript
// Verify sentinel configuration
RedisModule.forRoot({
  clients: {
    type: 'sentinel',
    sentinels: [
      { host: 'sentinel-1', port: 26379 },
      { host: 'sentinel-2', port: 26379 },
      { host: 'sentinel-3', port: 26379 },
    ],
    name: 'mymaster',  // Must match sentinel config
  },
})

Sentinel Authentication

Solutions:

typescript
RedisModule.forRoot({
  clients: {
    type: 'sentinel',
    sentinels: [...],
    name: 'mymaster',
    password: 'redis-password',
    sentinelOptions: {
      sentinelPassword: 'sentinel-password',  // Separate password
    },
  },
})

Plugin Issues

Plugin Dependency Missing

Symptoms:

  • Plugin "audit" depends on "cache" which is not registered

Cause: Plugin declares a dependency that isn't in the plugins array.

Solutions:

typescript
// ❌ Missing dependency
RedisModule.forRoot({
  clients: { host: 'localhost', port: 6379 },
  plugins: [
    new AuditPlugin(),  // depends on 'cache', but CachePlugin not registered
  ],
})

// ✅ Register all dependencies
RedisModule.forRoot({
  clients: { host: 'localhost', port: 6379 },
  plugins: [
    new CachePlugin(),   // Must come before dependents
    new AuditPlugin(),   // Now 'cache' dependency is satisfied
  ],
})

TIP

Plugin order in the array doesn't matter — the system automatically sorts by dependencies using topological sort. Just make sure all dependencies are present.

Circular Plugin Dependency

Symptoms:

  • Circular dependency detected among plugins: plugin-a, plugin-b

Cause: Two or more plugins depend on each other, forming a cycle.

Solutions:

typescript
// ❌ A depends on B, B depends on A
class PluginA implements IRedisXPlugin {
  readonly dependencies = ['plugin-b'];  // Circular!
}
class PluginB implements IRedisXPlugin {
  readonly dependencies = ['plugin-a'];  // Circular!
}

// ✅ Break the cycle — use moduleRef for optional cross-plugin access
class PluginA implements IRedisXPlugin {
  readonly dependencies = [];  // No hard dependency

  async onModuleInit(context: IPluginContext) {
    // Access plugin-b optionally
    if (context.hasPlugin('plugin-b')) {
      const pluginB = context.getPlugin('plugin-b');
    }
  }
}

Plugin Service Not Injectable

Symptoms:

  • Nest can't resolve dependencies of MyService (?). Please make sure that the argument LOCK_SERVICE at index [0] is available

Cause: Plugin not registered, or service token not exported.

Solutions:

  1. Ensure plugin is registered:
typescript
RedisModule.forRoot({
  clients: { host: 'localhost', port: 6379 },
  plugins: [
    new LocksPlugin(),  // Must be registered
  ],
})
  1. Use correct injection token:
typescript
import { LOCK_SERVICE, ILockService } from '@nestjs-redisx/locks';

@Injectable()
export class MyService {
  constructor(
    @Inject(LOCK_SERVICE) private readonly lockService: ILockService,
  ) {}
}

Plugin Lifecycle Hook Errors

Symptoms:

  • Plugin registration failed
  • Plugin initialization failed
  • Error during application startup

Solutions:

  1. Check plugin onRegister/onModuleInit for errors:
typescript
class MyPlugin implements IRedisXPlugin {
  async onModuleInit(context: IPluginContext) {
    try {
      // Your init logic
    } catch (error) {
      context.logger.error('Init failed', error);
      throw error;  // Let the system know
    }
  }
}
  1. Verify Redis is connected before accessing clients:
typescript
async onModuleInit(context: IPluginContext) {
  if (context.clientManager.hasClient('default')) {
    const client = await context.clientManager.getClient();
    // Safe to use client
  }
}

Performance Issues

High Latency

Symptoms:

  • Slow Redis operations
  • Timeouts on commands

Solutions:

  1. Check network latency:
bash
redis-cli --latency
  1. Use pipelining:
typescript
const pipeline = await this.redis.pipeline();
pipeline.get('key1');
pipeline.get('key2');
pipeline.get('key3');
const results = await pipeline.exec();
  1. Adjust timeouts:
typescript
RedisModule.forRoot({
  clients: {
    host: 'localhost',
    port: 6379,
    connectTimeout: 5000,   // Connection timeout
    commandTimeout: 3000,   // Command timeout
  },
})

Memory Issues

Symptoms:

  • OOM command not allowed
  • Redis memory full

Solutions:

  1. Check Redis memory:
bash
redis-cli INFO memory
  1. Set TTL on keys:
typescript
await this.redis.set('key', 'value', { ex: 3600 });  // 1 hour TTL
  1. Monitor key count:
typescript
const keyCount = await this.redis.dbsize();

Common Errors

ErrorCauseFix
ECONNREFUSEDRedis not runningStart Redis server
NOAUTHMissing passwordAdd password to config
WRONGPASSInvalid passwordCheck password in config
WRONGTYPEWrong data typeCheck key type first
MOVEDCluster redirectIncrease maxRedirections
CLUSTERDOWNCluster unavailableCheck cluster nodes, wait for recovery
READONLYWriting to replicaConnect to master
BUSYKEYTarget key existsDelete target key or use different name
OOMOut of memoryClear old keys, add memory
Plugin "x" depends on "y"...Missing plugin dependencyAdd required plugin to plugins array
Circular dependency detectedPlugins depend on each otherBreak the cycle, use hasPlugin() instead
Client "x" not foundWrong client nameVerify name matches config key

Debug Mode

Enable debug logging:

typescript
RedisModule.forRoot({
  clients: { host: 'localhost', port: 6379 },
  global: {
    debug: true,  // Enable debug logging
  },
})

Connection Test

typescript
import { Injectable } from '@nestjs/common';
import { RedisService } from '@nestjs-redisx/core';

@Injectable()
export class DebugService {
  constructor(private readonly redis: RedisService) {}

  async testConnection(): Promise<{
    connected: boolean;
    latency: number;
    serverInfo: string;
  }> {
    const start = Date.now();

    try {
      const pong = await this.redis.ping();
      const latency = Date.now() - start;
      const info = await this.redis.info('server');

      return {
        connected: pong === 'PONG',
        latency,
        serverInfo: info,
      };
    } catch (error) {
      return {
        connected: false,
        latency: -1,
        serverInfo: error.message,
      };
    }
  }
}

Redis CLI Commands

bash
# Check Redis is running
redis-cli ping

# Get server info
redis-cli INFO

# Monitor commands in real-time
redis-cli MONITOR

# Check memory usage
redis-cli INFO memory

# List all keys (use with caution)
redis-cli KEYS "*"

# Check cluster status
redis-cli CLUSTER INFO
redis-cli CLUSTER NODES

# Check sentinel status
redis-cli -p 26379 SENTINEL masters

Getting Help

If you're still stuck:

  1. Enable debug mode
  2. Check Redis server logs
  3. Verify network connectivity
  4. Test with redis-cli
  5. Review configuration
  6. Check for typos in client names

Next Steps

Released under the MIT License.