# Peek Messages (/sdks/java/how-to/queues/peek-messages)



## Overview [#overview]

Peeking lets you look at what's sitting in a queue without touching it — the messages stay exactly where they are, still waiting for whichever consumer eventually receives them. It's the tool you reach for when you need visibility into queue state — checking backlog depth, inspecting payloads while debugging a stuck pipeline, or building an operational dashboard — without risking a collision with real consumers competing for the same work.

`client.waiting(CHANNEL, maxMessages, waitTimeoutSeconds)` is a variant of the same receive call your consumers use, just in read-only mode: it returns a `QueueMessagesWaiting` snapshot of messages currently queued, but the broker never marks them as delivered, locks them, or starts a visibility timeout — so no `ack()` or `reject()` is needed or even possible.

**Gotchas:** peeked messages aren't reserved for you — a consumer can call `receiveQueueMessages` and remove them the instant after you peek, so treat the count as a point-in-time estimate, not a guarantee. Peek also won't surface messages already locked inside another consumer's in-flight receive, and `QueueMessagesWaiting.isError()` should always be checked before iterating `getMessages()` — an error indicates a broker-side failure, not an empty queue.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Java SDK installed (`implementation 'io.kubemq.sdk:kubemq-sdk-Java:3.1.1'` (Gradle) or Maven dependency from [Getting Started](/sdks/java))

## Code [#code]

```java title="PeekMessagesExample.java"
package io.kubemq.example.queues;

import io.kubemq.sdk.queues.*;

public class PeekMessagesExample {
    private static final String ADDRESS = "localhost:50000";
    private static final String CLIENT_ID = "java-queues-peek-messages-client";
    private static final String CHANNEL = "java-queues.peek-messages";

    public static void main(String[] args) {
        // Create a queues client connected to the KubeMQ server
        try (QueuesClient client = QueuesClient.builder().address(ADDRESS).clientId(CLIENT_ID).build()) {
            // Create the queue channel
            client.createQueuesChannel(CHANNEL);

            // Send messages to the queue
            for (int i = 1; i <= 3; i++) {
                client.sendQueueMessage(QueueMessage.builder()
                        .channel(CHANNEL).body(("Peek message " + i).getBytes()).build());
            }

            // Peek at waiting messages without consuming them (non-destructive)
            System.out.println("=== Peeking at waiting messages (non-destructive) ===");
            QueueMessagesWaiting waiting = client.waiting(CHANNEL, 10, 5);
            if (waiting.isError()) {
                System.err.println("Peek error: " + waiting.getError());
            } else {
                System.out.println("Messages waiting: " + waiting.getMessages().size());
                waiting.getMessages().forEach(msg ->
                    System.out.println("  ID: " + msg.getId() + ", Body: " + new String(msg.getBody())));
            }
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

```

## How It Works [#how-it-works]

* `client.waiting(CHANNEL, maxMessages, waitTimeoutSeconds)` is a non-destructive peek operation; it returns a `QueueMessagesWaiting` list of messages currently queued without consuming or locking them.
* Unlike `receiveQueueMessages`, peeked messages remain in the queue — no `ack()` or `reject()` is needed, and they are immediately visible to other consumers.
* `QueueMessagesWaiting.isError()` should always be checked before iterating `getMessages()`; an error indicates a broker-side failure (e.g. channel not found).

## Related [#related]

* [Pattern overview](/learn/queues/getting-started)
* [Java SDK Reference](/sdks/java/reference/queues)
* [Send & Receive](/sdks/java/tutorials/send-receive)
* [Ack All](/sdks/java/how-to/queues/ack-all)
