{"record":{"id":"0489c9ff2ed46f1c","repo":"apache/rocketmq","slug":"username-cannot-be-null","errorCode":null,"errorMessage":"username cannot be null.","messagePattern":"username cannot be null\\.","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"auth/src/main/java/org/apache/rocketmq/auth/authentication/chain/DefaultAuthenticationHandler.java","lineNumber":53,"sourceCode":"\n    private final AuthenticationMetadataProvider authenticationMetadataProvider;\n\n    public DefaultAuthenticationHandler(AuthConfig config, Supplier<?> metadataService) {\n        this.authenticationMetadataProvider = AuthenticationFactory.getMetadataProvider(config, metadataService);\n    }\n\n    @Override\n    public CompletableFuture<Void> handle(DefaultAuthenticationContext context,\n        HandlerChain<DefaultAuthenticationContext, CompletableFuture<Void>> chain) {\n        return getUser(context).thenAccept(user -> doAuthenticate(context, user));\n    }\n\n    protected CompletableFuture<User> getUser(DefaultAuthenticationContext context) {\n        if (this.authenticationMetadataProvider == null) {\n            throw new AuthenticationException(\"The authenticationMetadataProvider is not configured\");\n        }\n        if (StringUtils.isEmpty(context.getUsername())) {\n            throw new AuthenticationException(\"username cannot be null.\");\n        }\n        return this.authenticationMetadataProvider.getUser(context.getUsername());\n    }\n\n    protected void doAuthenticate(DefaultAuthenticationContext context, User user) {\n        if (user == null) {\n            throw new AuthenticationException(\"User:{} is not found.\", context.getUsername());\n        }\n        if (user.getUserStatus() == UserStatus.DISABLE) {\n            throw new AuthenticationException(\"User:{} is disabled.\", context.getUsername());\n        }\n        String signature = AclSigner.calSignature(context.getContent(), user.getPassword());\n        if (context.getSignature() == null\n            || !MessageDigest.isEqual(signature.getBytes(AclSigner.DEFAULT_CHARSET), context.getSignature().getBytes(AclSigner.DEFAULT_CHARSET))) {\n            throw new AuthenticationException(\"check signature failed.\");\n        }\n    }\n}","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/auth/src/main/java/org/apache/rocketmq/auth/authentication/chain/DefaultAuthenticationHandler.java#L35-L71","documentation":"The authentication context reached the handler but context.getUsername() is empty. The username is only set by the builder when a 'Credential=<user>' pair exists in the authorization header, so this means the client authenticated without presenting a credential - typically because the authorization header was absent, so the builder returned an early, empty context.","triggerScenarios":"Client sends a gRPC request with no authorization metadata (or one lacking Credential=...), while the server has authentication enabled and routes the request through DefaultAuthenticationHandler. Also hit when the header parse skipped the credential pair.","commonSituations":"Client SDK built without setting credentials (empty accessKey/secretKey); a plain gRPC health-check or admin tool hitting an endpoint that requires auth; forgetting to attach the credentials interceptor.","solutions":["Configure access credentials on the client so every request carries 'Credential=<username>' in the authorization metadata.","If the request is intentionally anonymous (e.g. internal health checks), disable authentication for that access path or whitelist it, rather than sending unsigned requests to an authenticated listener.","Verify the username field actually lands in the header: 'RocketMQ Credential=<user>,Signature=<sig>,DateTime=<dt>'."],"exampleFix":"// before\nClientConfigurationBuilder.build(new ClientConfiguration()); // no credentials\n\n// after\nClientConfiguration config = new ClientConfiguration();\nconfig.setCredentialsProvider(new StaticSessionCredentialsProvider(accessKey, secretKey));\nClientConfigurationBuilder.build(config);","handlingStrategy":"validation","validationCode":"// Client-side: refuse to send requests when credentials are unset\nif (accessKey == null || accessKey.isEmpty()) {\n    throw new IllegalStateException(\"credentials required: server has authentication enabled\");\n}","typeGuard":"boolean hasCredentials(ClientConfiguration c) { return c.getCredentialsProvider() != null && c.getCredentialsProvider().getCredentials() != null; }","tryCatchPattern":"catch (AuthenticationException e) { if message contains \"username cannot be null\" -> attach credentials provider and retry once; otherwise rethrow. }","preventionTips":["Wire the credentials interceptor at client construction, not per call","Add an integration test against an auth-enabled broker"],"tags":["rocketmq","authentication","credentials","grpc"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}