How to send messages to dlq from a service bus queue in a batch (java)?

Praneetha Chodey 0 Reputation points
2026-05-14T14:44:52.26+00:00

Scenario - I have a java application which uses a @ServiceBusQueueTrigger to get messages from a service bus queue. This is configured to get messages in a batch. Lets say there are 100 messages in the incoming batch and there is 1 bad message. I want to send this bad message to the dead letter sub queue for reviewing later. I cannot throw an exception because it ll fail my entire batch.

Example code:

@FunctionName("processMessage")
public void serviceBusProcess(
        @ServiceBusQueueTrigger(name = "message",
                                queueName = "%service_bus_queue_name%",
                                connection = "service_bus_connection",
                                cardinality = Cardinality.MANY
                                ) List<String> messages) {
    try {
        process(messages);
       
    } catch (Exception e) {
     
        throw e;
    }
}
Azure Service Bus
Azure Service Bus

An Azure service that provides cloud messaging as a service and hybrid integration.


2 answers

Sort by: Oldest
  1. Pravallika KV 18,850 Reputation points Microsoft External Staff Moderator
    2026-05-14T16:04:14.6766667+00:00

    Hi Praneetha Chodey,

    Thanks for reaching out to Microsoft Q&A.

    With cardinality = Cardinality.MANY, the Azure Functions runtime treats the batch as a single unit. If you throw an exception, the entire batch is abandoned/retried there’s no built-in per-message dead-letter handling in batch mode for Java Azure Functions.

    To dead-letter only the bad message, you need to process messages individually instead of relying on automatic batch settlement.

    A common approach is:

    1. Receive messages one by one (Cardinality.ONE)
    2. Use manual settlement with the Service Bus SDK
    3. Explicitly dead-letter the failed message

    Example using the Azure Service Bus SDK alongside Functions:

    @FunctionName("processMessage")
    public void serviceBusProcess(
        @ServiceBusQueueTrigger(
            name = "message",
            queueName = "%service_bus_queue_name%",
            connection = "service_bus_connection"
        ) String message,
        final ExecutionContext context
    ) {
    
        try {
            process(message);
    
        } catch (Exception ex) {
    
            // send to DLQ manually
            deadLetterMessage(message, ex);
    
            // DO NOT rethrow
        }
    }
    

    Alternatively, if you must keep batching for throughput, then the recommended pattern is:

    Catch exceptions per message inside the batch loop

    Send failed messages to:

    another “failed-messages” queue, or

      the Service Bus DLQ using the SDK
    
      
      Continue processing the rest of the batch
    
      
      Do not throw from the function
    ```Check below example:
    
    
    ```java
    @FunctionName("processMessage")
    public void serviceBusProcess(
        @ServiceBusQueueTrigger(
            name = "messages",
            queueName = "%service_bus_queue_name%",
            connection = "service_bus_connection",
            cardinality = Cardinality.MANY
        ) List<String> messages
    ) {
    
        for (String message : messages) {
    
            try {
                process(message);
    
            } catch (Exception ex) {
    
                // manually move bad message
                sendToDeadLetterQueue(message, ex);
    
                // continue processing remaining messages
            }
        }
    }
    

    However, note that with the built-in trigger binding you do not get access to the underlying ServiceBusReceivedMessage lock token in batch mode, so true native DLQ settlement (deadLetter()) is limited.

    For full control over:

    • abandon
    • complete
    • defer
    • dead-letter

    use the newer Azure Service Bus SDK for Java receiver client (ServiceBusProcessorClient or ServiceBusReceiverClient) instead of the Functions trigger abstraction.

    Hope this helps!


    If the resolution was helpful, kindly take a moment to click on User's imageand click on Yes for was this answer helpful. And, if you have any further query do let us know.

    Was this answer helpful?


  2. Vinodh247-1375 44,716 Reputation points Volunteer Moderator
    2026-05-14T16:09:28.18+00:00

    Hi ,

    Thanks for reaching out to Microsoft Q&A.

    You cannot selectively dead-letter a single message when using batch (Cardinality.MANY) processing in an azure function with azure service bus. The batch is treated as one unit by the trigger runtime, so throwing an exception affects the entire batch, not individual messages.

    If you need to move only the “bad” message to the DLQ, you have two practical options:

    1. Switch to single message processing (Cardinality.ONE) – this gives you control per message. You can then explicitly dead-letter using the Service Bus SDK (ServiceBusReceiver.deadLetterMessage()), without impacting others.

    Use SDK-based manual receive instead of trigger – receive messages via ServiceBusProcessorClient or ServiceBusReceiverClient, process them one by one inside your own loop, and explicitly call:

    complete() for good messages

      `deadLetter()` for bad messages
      
    

    In short, batch trigger = no per-message DLQ control. For your scenario, move to per message handling (either via single trigger or SDK) to isolate and dead-letter only the problematic message.

    Please 'Upvote'(Thumbs-up) and 'Accept' as answer if the reply was helpful. This will be benefitting other community members who face the same issue.

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.