qishibo/AnotherRedisDesktopManager · error · Error

You are in readonly mode! Unable to execute write command!

Error message

You are in readonly mode! Unable to execute write command!

What it means

This is a client-side guard inside the app's patched Redis.prototype.sendCommand (src/redisClient.js). When the connection was created with connectionReadOnly enabled, any command whose uppercase name exists in the writeCMD table from src/commands.js (DEL, SET, HSET, EXPIRE, PERSIST, RENAME, FLUSHDB, FLUSHALL, ...) is rejected before it ever reaches the server; command.reject() is called with this exact message. The command promise rejects, so every UI write action (edit value, delete, rename, set TTL, import keys) fails with it.

Solutions

  1. Edit the connection settings, uncheck Readonly, and reconnect - writes then pass through to the server.
  2. If readonly must stay on, route write operations to a separate writable connection instead of trying to bypass the guard.
  3. Check the exact command name against the writeCMD list in src/commands.js to confirm which operations are blocked.
  4. Programmatically inspect client.options.connectionReadOnly before issuing writes and warn the user early.

Example fix

// before
client.set(key, value).catch(e => showMessage(e.message)); // rejects: readonly mode

// after
import { writeCMD } from '@/commands.js';
if (client.options.connectionReadOnly && writeCMD['SET']) {
  showWarning('Connection is readonly - disable Readonly in connection settings to write.');
} else {
  client.set(key, value);
}
Defensive patterns

Strategy: validation

Validate before calling

import { writeCMD } from '@/commands.js';

// run before any write command
function assertWritable(client, commandName) {
  if (client.options.connectionReadOnly && writeCMD[commandName.toUpperCase()]) {
    throw new Error(`'${commandName}' is blocked: connection is readonly. Disable Readonly in connection settings.`);
  }
}

Type guard

const isReadonlyRejection = (e) => e instanceof Error && e.message.includes('readonly mode');

Try / catch

try {
  await client.set(key, value);
} catch (e) {
  if (isReadonlyRejection(e)) {
    promptUserToDisableReadonly(); // config fix, not a retry
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Connection saved with the Readonly option enabled, then performing any intercepted write: editing a key value (SET/HSET/LPUSH), deleting a key (DEL/UNLINK), renaming (RENAME), changing TTL (EXPIRE/PERSIST), FLUSHDB/FLUSHALL, or running a write command in the CLI tab.

Common situations: Connecting to production Redis with readonly deliberately checked to prevent accidents, then forgetting it is on; toggling readonly in the connection config without appreciating that the block is unconditional; shared prod credentials where only read access was intended.

Related errors


AI-assisted analysis of qishibo/AnotherRedisDesktopManager@c149855106 (2026-08-22). Data as JSON: /api/errors/84991661dd275d15. Report an issue: GitHub.

Appendix: source

Thrown at src/redisClient.js:17

import Redis from 'ioredis';
import { createTunnel } from 'tunnel-ssh';
import vue from '@/main.js';
import { remote } from 'electron';
import { writeCMD } from '@/commands.js';

const fs = require('fs');

const { sendCommand } = Redis.prototype;

// redis command log
Redis.prototype.sendCommand = function (...options) {
  const command = options[0];

  // readonly mode
  if (this.options.connectionReadOnly && writeCMD[command.name.toUpperCase()]) {
    command.reject(new Error('You are in readonly mode! Unable to execute write command!'));
    return command.promise;
  }

  // exec directly, without logs
  if (this.withoutLogging === true) {
    // invalid in next calling
    this.withoutLogging = false;
    return sendCommand.apply(this, options);
  }

  const start = performance.now();
  const response = sendCommand.apply(this, options);
  const cost = performance.now() - start;

  const record = {
    time: new Date(), connectionName: this.options.connectionName, command, cost,
  };
  vue.$bus.$emit('commandLog', record);

View on GitHub (pinned to c149855106)