Hi, Jiunn-Yang,

Thanks for the reply and your patience. The KIP looks good to me now.

Hi, Luke, Mickael,

Could you take a look at the KIP again and see if it makes sense to you?

Thanks,

Jun

On Tue, Aug 5, 2025 at 3:04 AM 黃竣陽 <s7133...@gmail.com> wrote:

> Hello Jun,
>
> Thanks for the reply,
>
> JR46: I have clarified the behavior for null and empty values, so users
> can
> understand the reasoning behind disallowing empty lists.
>
> JR48: I've updated the KIP accordingly.
>
> Best Regards,
> Jiunn-Yang
>
> > Jun Rao <j...@confluent.io.INVALID> 於 2025年8月5日 凌晨12:45 寫道:
> >
> > Hi, Jiunn-Yang,
> >
> > Thanks for the reply.
> >
> > JR46. "Currently, if plugin.path is set to an empty list, no
> user-specified
> > plugin locations are processed, but plugins from the parent classloader
> are
> > still loaded." Could you add why the current behavior is bad for the
> users?
> >
> > JR48. If we want to preserve the current behavior, we should remove the
> > following validation, right?
> >        if (validStrings.length == 0) {
> >            throw new IllegalArgumentException("Valid strings list cannot
> > be empty for in validator");
> >
> > Jun
> >
> > On Fri, Aug 1, 2025 at 6:47 PM 黃竣陽 <s7133...@gmail.com> wrote:
> >
> >> Hello Jun,
> >>
> >> Thanks for the reply.
> >>
> >> JR42, JR45, JR46, JR47: I have updated the KIP.
> >>
> >> JR43: If bootstrap.servers is empty for these configurations,
> >> it will fail when creating the AdminClient. I have updated the KIP to
> >> reflect this behavior.
> >>
> >> JR44: Thanks for pointing this out. Kafka will indeed fail at the
> storage
> >> format phase
> >> if the configuration is invalid. I have updated the KIP accordingly.
> >>
> >> JR48: The current in() method allows empty lists by default, so I
> believe
> >> setting isEmptyAllowed to true
> >> better preserves the original behavior. Therefore, I prefer not to
> change
> >> this default.
> >>
> >> Best Regards,
> >> Jiunn-Yang
> >>
> >>> Jun Rao <j...@confluent.io.INVALID> 於 2025年8月2日 凌晨2:38 寫道:
> >>>
> >>> Hi, Jiunn-Yang,
> >>>
> >>> Thanks for the reply. A few more comments.
> >>>
> >>> JR42. [6] [7] are not needed since currently an empty list already
> causes
> >>> an exception.
> >>>
> >>> JR43. Could you document the current behavior when bootstrap.servers is
> >>> empty in MirrorClientConfig and WorkerConfig?
> >>>
> >>> JR44. [12] seems incorrect. I set log.dir, but left log.dirs empty and
> >> got
> >>> the following.
> >>> bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c
> >>> config/server.properties
> >>> Exception in thread "main" java.lang.IllegalArgumentException:
> >> requirement
> >>> failed: At least one log directory must be defined via log.dirs or
> >> log.dir.
> >>>
> >>> bin/kafka-server-start.sh config/server.properties
> >>> [2025-08-01 11:31:20,097] INFO Registered
> >>> `kafka:type=kafka.Log4jController` MBean
> >>> (kafka.utils.Log4jControllerRegistration$)
> >>> [2025-08-01 11:31:20,238] ERROR Exiting Kafka due to fatal exception
> >>> (kafka.Kafka$)
> >>> java.lang.IllegalArgumentException: requirement failed: At least one
> log
> >>> directory must be defined via log.dirs or log.dir.
> >>>
> >>> JR45. Could you group all configs for WorkerConfig together?
> >>>
> >>> JR46. plugin.path: We have the following code. So, currently, it seems
> >> that
> >>> an empty list is allowed for plugin.path and we treat it by adding the
> >>> parent path of the classloader. It would be useful to justify why
> >>> disallowing empty is better for the users.
> >>>
> >>>   public static Set<PluginSource> pluginSources(Set<Path>
> >>> pluginLocations, ClassLoader classLoader, PluginClassLoaderFactory
> >> factory)
> >>> {
> >>>       Set<PluginSource> pluginSources = new LinkedHashSet<>();
> >>>       for (Path pluginLocation : pluginLocations) {
> >>>           try {
> >>>               pluginSources.add(isolatedPluginSource(pluginLocation,
> >>> classLoader, factory));
> >>>           } catch (InvalidPathException | MalformedURLException e) {
> >>>               log.error("Invalid path in plugin path: {}. Ignoring.",
> >>> pluginLocation, e);
> >>>           } catch (IOException e) {
> >>>               log.error("Could not get listing for plugin path: {}.
> >>> Ignoring.", pluginLocation, e);
> >>>           }
> >>>       }
> >>>
>  pluginSources.add(classpathPluginSource(classLoader.getParent()));
> >>>       return pluginSources;
> >>>   }
> >>>
> >>> JR47. typo in "Should not allow setting validStrings is empty"
> >>>
> >>> JR48. We should pass in isEmptyAllowed as false in the code below,
> right?
> >>>   public static ValidList in(String... validStrings) {
> >>>       if (validStrings.length == 0) {
> >>>           throw new IllegalArgumentException("Valid strings list cannot
> >>> be empty for in validator");
> >>>       }
> >>>       return new ValidList(List.of(validStrings), true, false);
> >>>   }
> >>>
> >>> Jun
> >>>
> >>> On Tue, Jul 29, 2025 at 8:53 AM 黃竣陽 <s7133...@gmail.com> wrote:
> >>>
> >>>> Hello Jun,
> >>>>
> >>>> Sorry for the late reply,
> >>>>
> >>>> JR40, JR41: I have updated the KIP based on your comments. Please
> take a
> >>>> look.
> >>>>
> >>>> Best Regards,
> >>>> Jiunn-Yang
> >>>>
> >>>>> Jun Rao <j...@confluent.io.INVALID> 於 2025年7月24日 凌晨2:56 寫道:
> >>>>>
> >>>>> Hi, Jiunn-Yang,
> >>>>>
> >>>>> Thanks for the reply.
> >>>>>
> >>>>> JR40. In the table, there are a few configs for which we now disallow
> >>>> empty
> >>>>> lists. It would be useful to document the current behavior for each
> of
> >>>> them
> >>>>> more accurately. It seems that they should all lead to some bad
> >> behavior.
> >>>>> For example, if log.dirs is empty, it seems that we can't create
> >> topics?
> >>>>> If group.coordinator.rebalance.protocols is empty, the group
> rebalance
> >>>>> protocol will fail?
> >>>>>
> >>>>> JR41. It would be useful to clean up the "Compatibility, Deprecation,
> >> and
> >>>>> Migration Plan" section a bit.
> >>>>> JR41.1 The migration plan has "Introduce a new properties
> >> isEmptyAllowed
> >>>> ,
> >>>>> isNullAllowed", which needs to be changed.
> >>>>> JR41.2 It started with "For users who configure an empty list", but
> not
> >>>> all
> >>>>> the bullet points are about empty lists.
> >>>>> JR41.3 To me, it would be useful to summarize why the behavior
> changes
> >>>> are
> >>>>> justified. We made 3 types of changes. (1) Disallow null. This is ok
> >>>> since
> >>>>> one can't really set a null value through a config file. (2) Disallow
> >>>>> duplicates. This is ok since it's rare and confusing. (3) Disallow
> >> empty.
> >>>>> Ideally, we want to claim that for those cases, they all lead to some
> >>>> other
> >>>>> errors or had behavior currently.
> >>>>>
> >>>>> Jun
> >>>>>
> >>>>> On Wed, Jul 23, 2025 at 4:42 AM 黃竣陽 <s7133...@gmail.com> wrote:
> >>>>>
> >>>>>> Hello Jun,
> >>>>>>
> >>>>>> Thanks for the reply.
> >>>>>>
> >>>>>> JR34 ,JR36, JR39: I’ve updated the KIP to reflect these changes.
> >>>>>>
> >>>>>> JR38: I clarified the following configurations:
> >>>>>> early.start.listeners: This config is optional and allows both null
> >> and
> >>>>>> empty lists.
> >>>>>> log.dirs and plugin.path: These are also optional, but only allow
> >>>>>> null—empty lists are not permitted.
> >>>>>>
> >>>>>> Best Regards,
> >>>>>> Jiunn-Yang
> >>>>>>
> >>>>>>> Jun Rao <j...@confluent.io.INVALID> 於 2025年7月23日 凌晨2:28 寫道:
> >>>>>>>
> >>>>>>> Hi, Jiunn-Yang and Chia-Ping,
> >>>>>>>
> >>>>>>> Thanks for the reply.
> >>>>>>>
> >>>>>>> JR34. Sounds good.
> >>>>>>>
> >>>>>>> JR36. Could you document that the default value for
> >>>>>>> sasl.oauthbearer.expected.audience and ssl.cipher.suites have been
> >>>>>> changed?
> >>>>>>>
> >>>>>>> JR38. My concern wasn't quite addressed. "If the configuration is
> >>>>>> optional,
> >>>>>>> we will reject any duplicate values in the list." This implies that
> >> if
> >>>> a
> >>>>>>> config is optional, we allow empty lists. However, for plugin.path,
> >> we
> >>>>>>> reject empty lists.
> >>>>>>>
> >>>>>>> JR39. We can remove the fields isEmptyAllowed and isNullAllowed
> since
> >>>>>> they
> >>>>>>> are not public facing.
> >>>>>>>
> >>>>>>> Jun
> >>>>>>>
> >>>>>>>
> >>>>>>> On Tue, Jul 22, 2025 at 4:26 AM 黃竣陽 <s7133...@gmail.com> wrote:
> >>>>>>>
> >>>>>>>> Hello Jun, Chia,
> >>>>>>>>
> >>>>>>>> Thanks for the reply,
> >>>>>>>>
> >>>>>>>> JR36: I’ve updated the following configurations:
> >>>>>>>> - sasl.oauthbearer.expected.audience
> >>>>>>>> - ssl.cipher.suites
> >>>>>>>> - ssl.enabled.protocols
> >>>>>>>> These now allow both empty and non-empty lists. Since the default
> >>>> values
> >>>>>>>> of
> >>>>>>>> sasl.oauthbearer.expected.audience and ssl.cipher.suites were
> >>>> previously
> >>>>>>>> null,
> >>>>>>>> I’ve updated their defaults to List.of() for consistency.
> >>>>>>>>
> >>>>>>>> JR37: A ClassCastException does not occur in MirrorClientConfig
> and
> >> it
> >>>>>>>> should be none.
> >>>>>>>> I’ve updated this in the KIP.
> >>>>>>>>
> >>>>>>>> JR38 & JR40: I’ve added a note below the table to indicate which
> >>>>>>>> configurations require special attention.
> >>>>>>>>
> >>>>>>>> JR39: Yes, these properties are package-private.
> >>>>>>>>
> >>>>>>>> Best Regards,
> >>>>>>>> Jiunn-Yang
> >>>>>>>>
> >>>>>>>>> Chia-Ping Tsai <chia7...@gmail.com> 於 2025年7月22日 下午6:04 寫道:
> >>>>>>>>>
> >>>>>>>>> JR34. Hmm, it seems that the code in taskConfigs() could return
> an
> >>>>>> empty
> >>>>>>>>> list for a task if knownSourceTopicPartitions is less than
> >> maxTasks,
> >>>>>>>>> Chia-Ping?
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> Yes, `MirrorSourceConnector#taskConfigs` could return an empty
> >> list,
> >>>>>>>> which
> >>>>>>>>> means no `MirrorSourceTask` can be created.
> >>>>>>>>>
> >>>>>>>>> By contrast, if any `MirrorSourceTask` is created, the configs
> used
> >>>> by
> >>>>>>>>> `MirrorSourceTask` must contain `task.assigned.partitions` with a
> >>>>>>>> non-empty
> >>>>>>>>> value.
> >>>>>>>>>
> >>>>>>>>> Jun Rao <j...@confluent.io.invalid> 於 2025年7月22日 週二 上午5:14寫道:
> >>>>>>>>>
> >>>>>>>>>> Hi, Jiunn-Yang and Chia-Ping,
> >>>>>>>>>>
> >>>>>>>>>> Thanks for the reply.
> >>>>>>>>>>
> >>>>>>>>>> JR34. Hmm, it seems that the code in taskConfigs() could return
> an
> >>>>>> empty
> >>>>>>>>>> list for a task if knownSourceTopicPartitions is less than
> >> maxTasks,
> >>>>>>>>>> Chia-Ping?
> >>>>>>>>>>
> >>>>>>>>>> JR36. Sounds good. Could you update the KIP? Also, should we do
> >> the
> >>>>>> same
> >>>>>>>>>> for ssl.cipher.suites and sasl.oauthbearer.expected.audience?
> >>>>>>>>>>
> >>>>>>>>>> JR37. Is it true that MirrorClientConfig.bootstrap.servers
> returns
> >>>>>>>>>> ClassCastException for null? It seems that null could be casted
> to
> >>>> any
> >>>>>>>>>> class.
> >>>>>>>>>>
> >>>>>>>>>> JR38. "If the configuration is optional, we will reject any
> >>>> duplicate
> >>>>>>>>>> values in the list." Could you clarify this? For example,
> >>>> plugin.path
> >>>>>> is
> >>>>>>>>>> optional, but with a default value. We reject duplicates as well
> >> as
> >>>>>>>> empty
> >>>>>>>>>> lists.
> >>>>>>>>>>
> >>>>>>>>>> JR39. isEmptyAllowed and isNullAllowed are not public fields,
> >> right?
> >>>>>>>> They
> >>>>>>>>>> are only public in the anyNonDuplicateValues() method.
> >>>>>>>>>>
> >>>>>>>>>> JR40. It would be useful to mention that if cleanup.policy is
> >> empty
> >>>>>> and
> >>>>>>>>>> remote.storage.enable is true, the local log segments will be
> >>>> cleaned
> >>>>>>>> based
> >>>>>>>>>> on log.local.retention.bytes and log.local.retention.ms.
> >>>>>>>>>>
> >>>>>>>>>> Jun
> >>>>>>>>>>
> >>>>>>>>>> On Fri, Jul 18, 2025 at 9:52 AM Chia-Ping Tsai <
> >> chia7...@gmail.com>
> >>>>>>>> wrote:
> >>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>> JR34: For these two configurations, setting an empty list
> feels
> >> a
> >>>>>> bit
> >>>>>>>>>>>> unintuitive. If an empty list is
> >>>>>>>>>>>> provided, the consumer will call the unsubscribe method, which
> >>>>>> doesn't
> >>>>>>>>>>>> seem appropriate given
> >>>>>>>>>>>> the documentation states: "Topic-partitions assigned to this
> >> task
> >>>> to
> >>>>>>>>>>>> replicate."
> >>>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>> agreed. Additionally, the source code [0] shows that it is not
> >>>>>> intended
> >>>>>>>>>> to
> >>>>>>>>>>> generate empty tps for the source task
> >>>>>>>>>>>
> >>>>>>>>>>> [0]
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>
> >>>>>>
> >>>>
> >>
> https://github.com/apache/kafka/blob/9b542b6ea21e84677a9292f250fc25f8b4162e6f/connect/mirror/src/main/java/org/apache/kafka/connect/mirror/MirrorSourceConnector.java#L202
> >>>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>
> >>>>>>
> >>>>
> >>>>
> >>
> >>
>
>

Reply via email to