eclipse-vertx/vert.x · error · IllegalStateException

address not specified

Error message

address not specified

What it means

sendReply is invoked when replying to a received message; the reply message must carry a destination address. EventBusImpl.sendReply throws this IllegalStateException when replyMessage.address() is null, i.e. a reply is being sent but no reply address was captured from the incoming message.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/eventbus/impl/EventBusImpl.java:359

  }

  private <T> void removeLocalRegistration(HandlerHolder<T> holder) {
    String address = holder.getHandler().address;
    handlerMap.compute(address, (key, val) -> {
      if (val == null) {
        return null;
      }
      ConcurrentCyclicSequence<HandlerHolder> next = val.remove(holder);
      return next.size() == 0 ? null : next;
    });
    if (holder.setRemoved() && holder.getContext().deploymentID() != null) {
      holder.getContext().removeCloseHook(holder.getHandler());
    }
  }

  protected <T> void sendReply(MessageImpl<?, T> replyMessage, DeliveryOptions options, ReplyHandler<T> replyHandler) {
    if (replyMessage.address() == null) {
      throw new IllegalStateException("address not specified");
    } else {
      sendOrPubInternal(new SendContext<>(vertx.getOrCreateContext(), replyMessage, options, replyHandler));
    }
  }

  protected <T> void sendOrPub(ContextInternal ctx, MessageImpl<?, T> message, DeliveryOptions options, Promise<Void> writePromise) {
    sendLocally(message, writePromise);
  }

  protected <T> void sendOrPub(SendContext<T> sendContext) {
    sendOrPub(sendContext.ctx, sendContext.message, sendContext.options, sendContext);
  }

  protected <T> void sendLocally(MessageImpl<?, T> message, Promise<Void> writePromise) {
    ReplyException failure = deliverMessageLocally(message);
    if (failure != null) {
      writePromise.tryFail(failure);
    } else {

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Reply using message.reply(body) / replyAndRequest() on the received Message instead of calling internal sendReply.
  2. If building a reply message manually, set its address (typically via generateReplyAddress() or the incoming message's replyAddress).
  3. Avoid subclassing/patching EventBus internals; use DeliveryOptions and the public Message API.

Example fix

// before
MessageImpl reply = new MessageImpl<>(null, body, options, bus); // null address
bus.sendReply(reply, options, handler);
// after
message.reply(body, new DeliveryOptions());
Defensive patterns

Strategy: type-guard

Validate before calling

Objects.requireNonNull(replyMessage.address(), "reply address must be set before sendReply");

Type guard

boolean canReply(Message<?, ?> m) {
  return m.address() != null || m.replyAddress() != null;
}

Try / catch

try {
  message.reply(body);
} catch (IllegalStateException e) {
  // no reply address; log and fall back to normal send
}

Prevention

When it happens

Trigger: Constructing a MessageImpl manually with a null address and passing it to sendReply/internal reply APIs; replying through a hand-rolled ReplyHandler without a generateReplyAddress()-assigned reply address; misuse of protected internal reply paths in custom EventBus subclasses.

Common situations: Custom EventBus implementations or deep-integration code that bypass Message.reply()/fail() and call internal methods directly; tests fabricating reply messages without setting the reply address.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/0b8e5d2d156e32f0. Report an issue: GitHub.