redis/jedis · error · MalformedMaintenanceEventException

Malformed MIGRATED push

Error message

Malformed MIGRATED push: <content>

What it means

MaintenancePushCodec.migrated() validates MIGRATED pushes, expecting [MIGRATED, Long seq, byte[] shards] (only 3 elements, no timestamp). If the shape or types differ, a malformed exception is thrown with the raw content so the unparseable payload can be diagnosed.

Solutions

  1. Upgrade/align jedis with the server's push schema version.
  2. Use the logged content to compare against the expected [MIGRATED, seq, shards] shape and report mismatches.
  3. Connect directly to the node to rule out intermediary mutation.
  4. If transient, reconnect — the codec operates per-push, not on shared state.
Defensive patterns

Strategy: validation

Validate before calling

static boolean isValidMigrated(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 MIGRATED push: {}", e.getMessage());
}

Prevention

When it happens

Trigger: A MIGRATED push with <3 elements, non-Long seq, or non-byte[] shards field arrives after a Redis Enterprise slot migration completes.

Common situations: Schema drift between client and server versions; proxies rewriting RESP arrays; corrupted or interleaved push frames on a shared connection.

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/be20f067152e88b5. Report an issue: GitHub.

Appendix: source

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

    if (c.size() < 4 || !(c.get(1) instanceof Long) || !(c.get(2) instanceof Long)
        || !(c.get(3) instanceof byte[])) {
      throw malformed("MIGRATING", c);
    }
    return new MigratingEvent((Long) c.get(1), (Long) c.get(2), shardIds(c, 3));
  }

  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) {

View on GitHub (pinned to 6dac31d4c2)