apache/rocketmq · error · AuthenticationException

datetime is null.

Error message

datetime is null.

What it means

Thrown while building the gRPC authentication context: the Authorization metadata header is present but the companion datetime metadata (GrpcConstants.DATE_TIME) is missing or empty. The datetime string is the content that gets HMAC-signed, so without it the server cannot verify the client signature. The builder therefore refuses to construct the context before any signature check happens.

Source

Thrown at auth/src/main/java/org/apache/rocketmq/auth/authentication/builder/DefaultAuthenticationContextBuilder.java:59

public class DefaultAuthenticationContextBuilder implements AuthenticationContextBuilder<DefaultAuthenticationContext> {

    private static final String CREDENTIAL = "Credential";
    private static final String SIGNATURE = "Signature";

    @Override
    public DefaultAuthenticationContext build(Metadata metadata, GeneratedMessageV3 request) {
        try {
            DefaultAuthenticationContext context = new DefaultAuthenticationContext();
            context.setChannelId(metadata.get(GrpcConstants.CHANNEL_ID));
            context.setRpcCode(request.getDescriptorForType().getFullName());
            String authorization = metadata.get(GrpcConstants.AUTHORIZATION);
            if (StringUtils.isEmpty(authorization)) {
                return context;
            }
            String datetime = metadata.get(GrpcConstants.DATE_TIME);
            if (StringUtils.isEmpty(datetime)) {
                throw new AuthenticationException("datetime is null.");
            }

            String[] result = authorization.split(CommonConstants.SPACE, 2);
            if (result.length != 2) {
                throw new AuthenticationException("authentication header is incorrect.");
            }
            String[] keyValues = result[1].split(CommonConstants.COMMA);
            for (String keyValue : keyValues) {
                String[] kv = keyValue.trim().split(CommonConstants.EQUAL, 2);
                int kvLength = kv.length;
                if (kv.length != 2) {
                    throw new AuthenticationException("authentication keyValues length is incorrect, actual length={}.", kvLength);
                }
                String authItem = kv[0];
                if (CREDENTIAL.equals(authItem)) {
                    String[] credential = kv[1].split(CommonConstants.SLASH);
                    int credentialActualLength = credential.length;
                    if (credentialActualLength == 0) {

View on GitHub (pinned to 293f588571)

Solutions

  1. Set the datetime metadata on every gRPC call, e.g. metadata.put(GrpcConstants.DATE_TIME, datetime) where datetime is the same string used when computing the client signature (typically formatted with DateTimeFormatter ofPattern('yyyyMMddHHmmss') in UTC).
  2. Use the official RocketMQ gRPC client SDK, which sets both authorization and datetime automatically in its credentials interceptor, instead of hand-writing the metadata.
  3. Verify no intermediary (gRPC proxy, custom ClientInterceptor, metadata whitelist) strips the datetime key between client and broker.

Example fix

// before
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("authorization", ASCII_STRING_MARSHALLER), authHeader);
// signature computed over a local datetime variable

// after
String datetime = LocalDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("datetime", ASCII_STRING_MARSHALLER), datetime);
metadata.put(Metadata.Key.of("authorization", ASCII_STRING_MARSHALLER), "RocketMQ Credential=" + username + ",Signature=" + signature + ",DateTime=" + datetime);
Defensive patterns

Strategy: validation

Validate before calling

// Before the gRPC call: ensure datetime metadata accompanies the authorization header
String datetime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
        .withZone(ZoneOffset.UTC).format(Instant.now());
if (authorizationHeader != null && !authorizationHeader.isEmpty()
        && (datetime == null || datetime.isEmpty())) {
    throw new IllegalStateException("datetime metadata is required when authorization is set");
}

Try / catch

catch (AuthenticationException e) when e.getMessage().contains("datetime is null") -> client-side: attach datetime metadata and retry once; surface otherwise.

Prevention

When it happens

Trigger: A gRPC client (e.g. RocketMQ 5.x remoting gRPC SDK) sends the 'authorization' metadata key but omits the 'datetime' metadata key, or sends it with an empty value. Triggered on any authenticated gRPC RPC once AUTHORIZATION is set, because datetime is checked immediately after a non-empty authorization header.

Common situations: Hand-rolled gRPC clients or custom interceptors that only copy the authorization header; SDK versions where the signer sets datetime but a proxy/loan balancer strips unknown metadata keys; client code that builds metadata manually and forgets the datetime entry that the signature was computed over.

Related errors


AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14). Data as JSON: /api/errors/a37fd1aa48dd8264. Report an issue: GitHub.