redis/jedis · error · MalformedMaintenanceEventException

Malformed FAILED_OVER push

Error message

Malformed FAILED_OVER push: <content>

What it means

MaintenancePushCodec.failedOver() validates FAILED_OVER pushes, expecting [FAILED_OVER, Long seq, byte[] shards]. A payload of the wrong shape or field types throws a malformed exception including the raw content.

Solutions

  1. Upgrade jedis to match the server's maintenance push format.
  2. Compare the error's logged content against the documented [FAILED_OVER, seq, shards] shape and file an issue if valid-looking.
  3. Rule out proxies rewriting RESP push arrays by connecting directly.
  4. Reconnect after the failover window; subsequent pushes should parse if versions match.
Defensive patterns

Strategy: validation

Validate before calling

static boolean isValidFailedOver(List<Object> c) {
  return c.size() >= 3 && c.get(1) instanceof Long && c.get(2) instanceof byte[];
}

Try / catch

try {
  handle(codec.decode(push));
} catch (JedisException e) {
  log.warn("Dropping malformed FAILED_OVER push: {}", e.getMessage());
}

Prevention

When it happens

Trigger: A FAILED_OVER push arrives with <3 elements, a non-Long seq, or a shards field that is not byte[] — after a Redis Enterprise failover completes.

Common situations: Version mismatch between jedis and the Redis Enterprise cluster emitting maintenance pushes; intermediaries mutating push payloads; corrupted RESP3 push streams under load.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08). Data as JSON: /api/errors/645721ee04f6942b. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/redis/clients/jedis/MaintenancePushCodec.java:104

  private static MaintenanceEvent failingOver(List<Object> c) { // [FAILING_OVER, seq, time_s,
                                                                // shards]
    if (c.size() < 4 || !(c.get(1) instanceof Long) || !(c.get(2) instanceof Long)
        || !(c.get(3) instanceof byte[])) {
      throw malformed("FAILING_OVER", c);
    }
    return new FailingOverEvent((Long) c.get(1), (Long) c.get(2), shardIds(c, 3));
  }

  private static MaintenanceEvent migrated(List<Object> c) { // [MIGRATED, seq, shards]
    if (c.size() < 3 || !(c.get(1) instanceof Long) || !(c.get(2) instanceof byte[])) {
      throw malformed("MIGRATED", c);
    }
    return new MigratedEvent((Long) c.get(1), shardIds(c, 2));
  }

  private static MaintenanceEvent failedOver(List<Object> c) { // [FAILED_OVER, seq, shards]
    if (c.size() < 3 || !(c.get(1) instanceof Long) || !(c.get(2) instanceof byte[])) {
      throw malformed("FAILED_OVER", c);
    }
    return new FailedOverEvent((Long) c.get(1), shardIds(c, 2));
  }

  /** Diagnostic shard-id list (stringified JSON array), logging only; required on the wire. */
  private static String shardIds(List<Object> c, int i) {
    return SafeEncoder.encode((byte[]) c.get(i));
  }

  /** MOVING target {@code host:port}; throws when the target is absent or unparseable. */
  private static HostAndPort parseHostPort(List<Object> c, int i) {
    if (i >= c.size() || !(c.get(i) instanceof byte[])) {
      throw new MalformedMaintenanceEventException(
          "MOVING target must be a host:port byte[] at index " + i + ": " + c);
    }
    try {
      return HostAndPort.from(SafeEncoder.encode((byte[]) c.get(i)));
    } catch (Exception e) {

View on GitHub (pinned to 6dac31d4c2)