pinpoint-apm/pinpoint · warning

Command complete before establishment

Error message

Command complete before establishment

What it means

The collector's command stream onCompleted callback fires when the client half-closes the stream. If the connection (GrpcAgentConnection) was never established/registered before completion, the handler logs 'Command complete before establishment'. Unlike the other errors in this class this is only a server-side warning log; no gRPC error is sent and no exception is thrown to the caller.

Solutions

  1. Check the agent logs for why the command stream was closed immediately after connecting (crash, OOM, config error)
  2. Ensure the agent stays connected long enough for handshake/registration; fix any rapid reconnect loop
  3. Ignore this warning if it coincides with normal agent shutdown or collector redeploy; it is informational for stray completes
  4. If a custom client opens the stream, keep it open and complete it only after the session is finished
Defensive patterns

Strategy: try-catch

Try / catch

// this is a server-side warning, not a thrown error; guard the lifecycle instead
serverCallStreamObserver.setOnCancelHandler(() -> {
    GrpcAgentConnection conn = connRef.get();
    if (conn != null) { // handles the 'not established' case gracefully
        agentConnectionRepository.remove(conn);
    }
});

Prevention

When it happens

Trigger: The agent closes/completes its command stream (or the call ends) before the request observer registered the GrpcAgentConnection in the connection repository, e.g. the stream is completed immediately after handleCommand/handleCommandV2 returns or the registration raced with shutdown.

Common situations: Agent connecting and instantly disconnecting (crash loop, deploy restart); a health-check or misconfigured client opening and closing the stream without sending messages; network flaps during collector restart where close events arrive before registration completes.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/0e423d9bae6cb474. Report an issue: GitHub.

Appendix: source

Thrown at realtime/realtime-collector/src/main/java/com/navercorp/pinpoint/realtime/collector/receiver/grpc/GrpcCommandService.java:263

    }

    private void handleOnError(Throwable t, GrpcAgentConnection conn) {
        if (conn == null) {
            logger.warn("Command error before establishment");
            return;
        }

        final Status status = Status.fromThrowable(t);
        Metadata metadata = Status.trailersFromThrowable(t);

        logger.info("Failed to command stream, {} => local, {} {}",
                conn.getClusterKey(), status, metadata);

    }

    private void handleOnCompleted(GrpcAgentConnection conn) {
        if (conn == null) {
            logger.warn("Command complete before establishment");
            return;
        }

        logger.info("{} => local. onCompleted", conn.getClusterKey());
    }

    @Override
    public void commandEcho(PCmdEchoResponse response, StreamObserver<Empty> responseObserver) {
        long sinkId = response.getCommonResponse().getResponseId();
        final EchoPublisher publisher = this.echoSinkRepo.get(sinkId);
        emitMono(response, responseObserver, publisher);
        this.echoSinkRepo.invalidate(sinkId);
    }

    @Override
    public void commandActiveThreadDump(PCmdActiveThreadDumpRes response, StreamObserver<Empty> responseObserver) {
        long sinkId = response.getCommonResponse().getResponseId();
        final ActiveThreadDumpPublisher publisher = this.activeThreadDumpSinkRepo.get(sinkId);

View on GitHub (pinned to 744c3d3075)