kafka-ui icon indicating copy to clipboard operation
kafka-ui copied to clipboard

Fresh install: adding cluster ends with status 400 "config.properties.auth.oauth2 can not be null"

Open OrionFOTL opened this issue 5 days ago • 2 comments

Issue submitter TODO list

  • [x] I've looked up my issue in FAQ
  • [x] I've searched for an already existing issues here
  • [x] I've tried running main-labeled docker image and the issue still persists there
  • [x] I'm running a supported version of the application which is listed here

Describe the bug (actual behavior)

When I run kafbat on completely basic settings lifted straight from README's "Quick start", clicking Submit on the new cluster form ends with status 400, with message "Fields validation failure", with details complaining about config.properties.auth.oauth2 being null.

The PUT request that attempts to add the cluster contains "auth": { "type": "DISABLED", "oauth2": null } (this is about kafbat's auth, not kafka's). The validation complains about oauth2 being null, but it should be allowed to be null if I don't have kafbat auth.

Expected behavior

I expect the cluster to be added, even when I run kafbat without auth.

Your installation details

docker run -it -p 8080:8080 -e DYNAMIC_CONFIG_ENABLED=true ghcr.io/kafbat/kafka-ui (v1.4.2) No actual running Kafka needed to reproduce, but the problem persist all the same if I enter connection to an actual Kafka.

Steps to reproduce

  1. docker run -it -p 8080:8080 -e DYNAMIC_CONFIG_ENABLED=true ghcr.io/kafbat/kafka-ui
  2. Open http://localhost:8080/ui/clusters/create-new-cluster
  3. Bootstrap servers: localhost, 9093 (no other cluster config needed, and it doesn't matter if something actually runs there)
  4. Press Submit
  5. 400 Bad Request: Fields validation failure

Screenshots

Image

Logs

Clicking Submit results in this request: PUT http://localhost:8080/api/config

With this body:

{
  "config": {
    "properties": {
      "auth": {
        "type": "DISABLED",
        "oauth2": null           // type=DISABLED and oauth2=null, as expected - but causes validation fail
      },
      "rbac": {
        "roles": []
      },
      "webclient": {},
      "kafka": {
        "clusters": [
          {
            "name": "Test",
            "bootstrapServers": "localhost:9093",
            "properties": {},
            "readOnly": false
          }
        ]
      }
    }
  }
}

And this response (status 400):

{
  "code": 4001,
  "message": "Fields validation failure",
  "timestamp": 1764153973576,
  "requestId": "f0ddeda3-66",
  "fieldsErrors": [
    {
      "fieldName": "config.properties.auth.oauth2",
      "restrictions": [
        "nie może mieć wartości null"
      ]
    }
  ],
  "stackTrace": "org.springframework.web.bind.support.WebExchangeBindException: Validation failed for argument at index 0 in method: public reactor.core.publisher.Mono<org.springframework.http.ResponseEntity<java.lang.Void>> io.kafbat.ui.controller.ApplicationConfigController.restartWithConfig(reactor.core.publisher.Mono<io.kafbat.ui.model.RestartRequestDTO>,org.springframework.web.server.ServerWebExchange), with 1 error(s): [Field error in object 'restartRequestDTOMono' on field 'config.properties.auth.oauth2': rejected value [null]; codes [NotNull.restartRequestDTOMono.config.properties.auth.oauth2,NotNull.config.properties.auth.oauth2,NotNull.oauth2,NotNull.io.kafbat.ui.model.ApplicationConfigPropertiesAuthOauth2DTO,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [restartRequestDTOMono.config.properties.auth.oauth2,config.properties.auth.oauth2]; arguments []; default message [config.properties.auth.oauth2]]; default message [nie może mieć wartości null]] \n\tat org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.validate(AbstractMessageReaderArgumentResolver.java:289)\n\tSuppressed: The stacktrace has been enhanced by Reactor, refer to additional information below: \nError has been observed at the following site(s):\n\t*__checkpoint ⇢ Handler io.kafbat.ui.controller.ApplicationConfigController#restartWithConfig(Mono, ServerWebExchange) [DispatcherHandler]\n\t*__checkpoint ⇢ io.kafbat.ui.config.CorsGlobalConfiguration$$Lambda/0x00007b5ed6652fb8 [DefaultWebFilterChain]\n\t*__checkpoint ⇢ io.kafbat.ui.config.ReadOnlyModeFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ io.kafbat.ui.config.CustomWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ AuthorizationWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ ExceptionTranslationWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ LogoutWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ ServerRequestCacheWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ ReactorContextWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ HttpHeaderWriterWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]\n\t*__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]\n\t*__checkpoint ⇢ HTTP PUT \"/api/config\" [ExceptionHandlingWebHandler]\nOriginal Stack Trace:\n\t\tat org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.validate(AbstractMessageReaderArgumentResolver.java:289)\n\t\tat org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.lambda$readBody$5(AbstractMessageReaderArgumentResolver.java:210)\n\t\tat reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185)\n\t\tat reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)\n\t\tat reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)\n\t\tat reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299)\n\t\tat reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337)\n\t\tat reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2096)\n\t\tat reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)\n\t\tat reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)\n\t\tat reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:481)\n\t\tat reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:273)\n\t\tat reactor.netty.channel.FluxReceive.request(FluxReceive.java:131)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164)\n\t\tat reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164)\n\t\tat reactor.core.publisher.Operators$BaseFluxToMonoOperator.request(Operators.java:2066)\n\t\tat reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.request(FluxFilterFuseable.java:411)\n\t\tat reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360)\n\t\tat reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:136)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)\n\t\tat reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2366)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)\n\t\tat reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:101)\n\t\tat reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265)\n\t\tat reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onSubscribe(FluxFilterFuseable.java:305)\n\t\tat reactor.core.publisher.Operators$BaseFluxToMonoOperator.onSubscribe(Operators.java:2050)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92)\n\t\tat reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:171)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92)\n\t\tat reactor.netty.channel.FluxReceive.startReceiver(FluxReceive.java:170)\n\t\tat reactor.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:148)\n\t\tat io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)\n\t\tat io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)\n\t\tat io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)\n\t\tat io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:405)\n\t\tat io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:998)\n\t\tat io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)\n\t\tat io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)\n\t\tat java.base/java.lang.Thread.run(Thread.java:1583)\n"
}

Additional context

Issue doesn't happen on v1.3.0

OrionFOTL avatar Nov 26 '25 11:11 OrionFOTL