Skip to content

Conversation

@m1a2st
Copy link
Collaborator

@m1a2st m1a2st commented Nov 27, 2025

This PR updates the behavior of Admin.incrementalAlterConfigs() to be
consistent when invoked using bootstrap servers versus bootstrap
controllers. The following changes apply specifically when using a
bootstrap controller:

  1. Null Config Values (DELETE Only)
    A null config value is allowed only when used with
    AlterConfigOp.OpType.DELETE.
    Supplying null with any other operation type will now result in an
    InvalidRequestException.

  2. Duplicate Config Names
    Providing duplicate configuration names within the same resource will
    now fail with an InvalidRequestException.

  3. Unknown Resource Types
    Requests containing unknown resource types will now fail with an
    InvalidRequestException.

These changes ensure the controller-based Admin API behaves consistently
and predictably, aligning with broker-side validation rules.

FYI: #20960

@github-actions github-actions bot added triage PRs from the community core Kafka Broker labels Nov 27, 2025
Copy link
Member

@chia7712 chia7712 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m1a2st could you take a look at the failed test testInvalidIncrementalAlterConfigsResources?

@github-actions github-actions bot removed the triage PRs from the community label Nov 28, 2025
@m1a2st m1a2st changed the title KAFKA-19931 inconsistency in handling the null config value [WIP] KAFKA-19931 inconsistency in handling the null config value Nov 28, 2025
Copy link
Contributor

@junrao junrao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m1a2st : Thanks for the PR. Left a comment.

altersByName.put(config.name, new util.AbstractMap.SimpleEntry[AlterConfigOp.OpType, String](
AlterConfigOp.OpType.forId(config.configOperation), config.value))
if (!nullUpdates.isEmpty) {
throw new InvalidRequestException("Null value not supported for : " +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to just set the error response here instead of throwing?

} catch {
case t: Throwable => ApiError.fromThrowable(t)
try {
val nullUpdates = new util.ArrayList[String]()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, there are quite a few pre-processing checks in ConfigAdminManager. The doc says the following. Could we restructure the code between ConfigAdminManager and ControllerApis to (1) avoid duplicates logic in verification (2) prevent missing verification in one of the two places in the future?

        // BROKER_LOGGER requests always go to a specific, constant broker or controller node.
        //
        // BROKER resource changes for a specific (non-default) resource go to either that specific
        // node (if using bootstrap.servers), or directly to the active controller (if using
        // bootstrap.controllers)
        //
        // All other requests go to the least loaded broker (if using bootstrap.servers) or the
        // active controller (if using bootstrap.controllers)

resource)
ApiError.NONE
} catch {
case t: Throwable => ApiError.fromThrowable(t)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not throwing the exception directly? The onError method should handle it, right?

setResourceType(ConfigResource.Type.BROKER.id()),
new AlterConfigsResourceResponse().
setErrorCode(UNSUPPORTED_VERSION.code()).
setErrorCode(INVALID_REQUEST.code()).
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The controller error code should match the broker error code.

Copy link
Member

@chia7712 chia7712 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m1a2st would you mind updating the upgrade.html to inform users about this behaviour change?

configChanges: util.HashMap[ConfigResource, util.Map[String, Entry[AlterConfigOp.OpType, String]]],
response: IncrementalAlterConfigsResponseData
): Unit = {
if (!duplicateResources.contains(configResource)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use configChanges instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant that the configChanges collection could be used to check the duplicates, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old logic worked in three steps:

  1. The first occurrence of a configResource is added to the map.
  2. The second occurrence of the same configResource is removed from the map, added to duplicateValue, and written to the response.
  3. The third and any subsequent occurrences of that configResource are ignored entirely.

Given this behavior, I think we cannot rely solely on a map to implement this logic.

@chia7712
Copy link
Member

chia7712 commented Dec 8, 2025

@m1a2st I noticed another inconsistent behavior.

The following code fails on the broker but succeeds on the controller.

  admin.incrementalAlterConfigs(Map.of(
                    new ConfigResource(ConfigResource.Type.TOPIC, "chia"),
                    List.of(new AlterConfigOp(new ConfigEntry("cleanup.policy", "compact"), OpType.SET),
                            new AlterConfigOp(new ConfigEntry("cleanup.policy", "compact"), OpType.SET),
                            new AlterConfigOp(new ConfigEntry("flush.ms", "11000"), OpType.SET))
            )

@chia7712
Copy link
Member

chia7712 commented Dec 8, 2025

The following code fails on the broker but succeeds on the controller.

It appears this behaviour gets fixed also. @m1a2st would you mind updating the PR description and add the integration test ?

@m1a2st m1a2st changed the title KAFKA-19931 inconsistency in handling the null config value KAFKA-19931 Inconsistency in handling the null config value, duplicate value, error code Dec 8, 2025
Copy link
Contributor

@junrao junrao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m1a2st : Thanks for the PR. Since this is a behavior change, it's probably better to do a KIP so that more people are aware of it.

@m1a2st
Copy link
Collaborator Author

m1a2st commented Dec 15, 2025

Thanks for @junrao comment, I have started a discussion thread.

FYI: https://lists.apache.org/thread/lqn0xw0zdfwl9m990otjvswzqh5bmy8v

@chia7712
Copy link
Member

@m1a2st I noticed another inconsistency related to this patch. The controller does not validate the dynamic configurations when handling requests, which results in a misleading success response. By contrast, the broker checks the dynamic configurations immediately upon receiving the request, allowing users to catch invalid requests early. Would you mind fixing this as well?

@m1a2st m1a2st changed the title KAFKA-19931 Inconsistency in handling the null config value, duplicate value, error code KAFKA-19931 Align broker and controller behavior for the Admin.incrementalAlterConfigs API Dec 20, 2025
@m1a2st
Copy link
Collaborator Author

m1a2st commented Dec 20, 2025

I noticed another inconsistency related to this patch. The controller does not validate the dynamic configurations when handling requests, which results in a misleading success response. By contrast, the broker checks the dynamic configurations immediately upon receiving the request, allowing users to catch invalid requests early. Would you mind fixing this as well?

I also added this inconsistent behavior to the KIP, and I can align it as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Kafka Broker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants