Skip to content

fix(topics): clamp default replication factor to broker count#2420

Merged
c-julin merged 5 commits intomasterfrom
jc/topic-rf-broker-clamp
Apr 28, 2026
Merged

fix(topics): clamp default replication factor to broker count#2420
c-julin merged 5 commits intomasterfrom
jc/topic-rf-broker-clamp

Conversation

@c-julin
Copy link
Copy Markdown
Contributor

@c-julin c-julin commented Apr 23, 2026

Summary

Three topic-create surfaces in Console hardcoded `replicationFactor: 3`. On single-broker clusters (local-byoc dev environments, degraded prod edges) that caused CreateTopic to fail with "not enough replicas". The RPCN onboarding form was the most visible case because the RF input is rendered `readOnly` — users could see the `3` but had no way to change it.

Files changed:

  • `pages/rp-connect/onboarding/add-topic-step.tsx` — override `TOPIC_FORM_DEFAULTS.replicationFactor` at form init with `min(3, brokersOnline)`. This is the user-visible fix: the readOnly field now shows the correct value for single-broker clusters.
  • `pages/topics/create-topic-modal.tsx` — new topic-create modal; clamp RF inline.
  • `pages/mcp-servers/details/remote-mcp-inspector-tab.tsx` — MCP inspector's inline topic-create flow; clamp RF inline.

All three use `useGetKafkaInfoQuery` to read `brokersOnline` and fall back to the original `3` while the query is loading. On 3+ broker clusters the behavior is unchanged.

Note: the legacy `pages/topics/CreateTopicModal/create-topic-modal.tsx` already reads the default from the broker's `default.replication.factor` config, so it's already correct provided the broker config is correct.

Test plan

  • `bun run test:ci` (unit): 755/755 passed on the branch
  • `bun run lint` auto-sorted imports; no new lint findings introduced by this change
  • Manual verification on a 1-broker local-byoc cluster: RPCN onboarding → Add Topic should show RF=1 (readOnly), CreateTopic succeeds
  • Manual verification on a 3-broker cluster: RPCN onboarding shows RF=3 as before

CreateTopic defaulted replicationFactor to 3 in both the topic-create
modal and the MCP inspector's "create new topic" flow. On single-broker
clusters (local-byoc dev environments, etc.) that rejected the request
with "not enough replicas". Clamp the default to min(3, brokersOnline)
and fall back to 3 while KafkaInfo is loading.
@c-julin c-julin closed this Apr 23, 2026
The RPCN onboarding Add Topic step spread TOPIC_FORM_DEFAULTS
(replicationFactor: 3) into the form and renders the RF field as
readOnly in AdvancedTopicSettings. On single-broker clusters
(local-byoc dev environments) that meant the user saw RF=3 with no
way to edit, and CreateTopic failed with "not enough replicas".

Override replicationFactor at form init with min(default, brokersOnline)
via useGetKafkaInfoQuery so the readOnly value matches what the broker
can actually satisfy.
@c-julin c-julin reopened this Apr 23, 2026
c-julin added 2 commits April 23, 2026 16:48
Scope back to the user-visible topic-create paths only. The MCP
inspector's "create new topic" flow is out of scope for this PR.
useForm captures defaultValues at mount; when the KafkaInfo query
resolves after mount the RF field stays at its initial 3. Pass
defaultValues through both `defaultValues` and `values` with
`resetOptions: { keepDirtyValues: true }` so the form reactively
picks up the clamped replicationFactor once brokersOnline is known,
without clobbering fields the user has already edited.
@c-julin
Copy link
Copy Markdown
Contributor Author

c-julin commented Apr 28, 2026

@claude review

@claude
Copy link
Copy Markdown

claude Bot commented Apr 28, 2026

Claude finished @c-julin's task in 3m 0s —— View job


Code Review

  • Gather context and read changed files
  • Review implementation
  • Post feedback

The fix is correct and the approach is sound. Two issues worth addressing before merge, plus some minor notes.


Potential bug — resetOptions: { keepDirtyValues: true } affects the existing-topic reset

In add-topic-step.tsx, keepDirtyValues: true is set at the form level to protect dirty fields when kafkaInfo lands late. But resetOptions in useForm applies as defaults to all form.reset() calls, including the one on line 169 that populates the form with an existing topic's config:

// add-topic-step.tsx:169
form.reset(allTopicValues, { keepDefaultValues: false });
// → effective options: { keepDefaultValues: false, keepDirtyValues: true }

If a user types something in an advanced setting field before selecting an existing topic, the keepDirtyValues: true default would preserve their typed values instead of overwriting them with the topic's actual config. That's the opposite of the intended behavior for this path.

Fix: override keepDirtyValues explicitly in the existing-topic reset:

form.reset(allTopicValues, { keepDefaultValues: false, keepDirtyValues: false });

Fix this →


Missing test coverage for the RF clamp

add-topic-step.test.tsx has solid coverage for the form mechanics but nothing tests the new clamping logic. Since the RF field is readOnly and the whole motivation of this PR is that users can't fix the wrong value, a test catching a regression here seems important:

it('clamps replicationFactor to brokersOnline on single-broker cluster', async () => {
  // mock useGetKafkaInfoQuery to return brokersOnline: 1
  // submit with a new topic
  // assert createTopic was called with replicationFactor: 1
});

Minor notes

brokersOnline === 0 comment drift (create-topic-modal.tsx:49-51): The comment says "Fall back to the default if the KafkaInfo query hasn't resolved yet." The same branch also fires when the query resolves to brokersOnline: 0 (all brokers offline). In that case the fallback to RF=3 is benign (topic creation would fail regardless), but the comment slightly misrepresents the condition.

MCP inspector (acknowledged in PR description): remote-mcp-inspector-tab.tsx is still hardcoded to DEFAULT_TOPIC_REPLICATION_FACTOR after the revert. Worth a follow-up issue if local-byoc users hit this path.

create-topic-modal.tsxformOpts.onSubmit closure: replicationFactor is captured inside formOpts.onSubmit. This is fine as long as useAppForm updates its internal options ref each render (standard TanStack Form behaviour), so the latest value is used at submit time. Worth a sanity check against the useAppForm wrapper if not already confirmed.


Overall: The root fix (clamping RF to min(3, brokersOnline)) is correct, and the values + keepDirtyValues approach for handling late-arriving kafkaInfo in the RPCN form is the right RHF pattern. The resetOptions interaction with the existing-topic reset path is the one thing I'd want resolved before merge.

Address PR review feedback on #2420. The form-level
`resetOptions: { keepDirtyValues: true }` (added so dirty fields
survive the late `kafkaInfo` re-init) was leaking into the
existing-topic-selected reset, where dirty fields should be
overwritten by the selected topic's actual config.

Also tighten the RF clamp comment in `create-topic-modal.tsx` to
cover the all-brokers-offline case, not just the loading case.

Refs UX-1208.
@c-julin c-julin merged commit 2389de8 into master Apr 28, 2026
17 checks passed
@c-julin c-julin deleted the jc/topic-rf-broker-clamp branch April 28, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants