Skip to content

kafka: use default option when meeting authorization and ACLs fails#5562

Merged
ti-chi-bot[bot] merged 2 commits into
pingcap:masterfrom
wk989898:kafka-acl
Jul 6, 2026
Merged

kafka: use default option when meeting authorization and ACLs fails#5562
ti-chi-bot[bot] merged 2 commits into
pingcap:masterfrom
wk989898:kafka-acl

Conversation

@wk989898

@wk989898 wk989898 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: close #5563

What is changed and how it works?

If ticdc fails to authorize acl on the kafka server, try using the default option instead of throwing an error when creating the changefeed. The change will fail later.
This is to prevent the changefeed from being created if the user does not grant the relevant acl permissions.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
Kafka Bad config Topic DescribeConfigs granted? changefeed create Post-create result
2.8.0 max.message.bytes=1024 No Success warning, broker rejects large DML with message-too-large
2.8.0 max.message.bytes=1024 Yes Success warning, TiCDC detects ErrMessageTooLarge using adjusted maxMessageBytes=896
3.7.0 max.message.bytes=1024 No Success warning, broker rejects large DML with message-too-large
3.7.0 max.message.bytes=1024 Yes Success warning, TiCDC detects ErrMessageTooLarge using adjusted maxMessageBytes=896
2.8.0 min.insync.replicas=2, RF=1 No Success warning, Kafka send fails after DDL
2.8.0 min.insync.replicas=2, RF=1 Yes Fail at create TiCDC rejects invalid config before creating the changefeed
3.7.0 min.insync.replicas=2, RF=1 No Success normal in this local broker test
3.7.0 min.insync.replicas=2, RF=1 Yes Fail at create TiCDC rejects invalid config before creating the changefeed

Questions

Will it cause performance regression or break compatibility?
Do you need to update user documentation, design documentation or monitoring documentation?

Release note

Avoid creating changefeed when meeting authorization and ACL failure

Summary by CodeRabbit

  • Bug Fixes
    • Improved resilience when reading Kafka configuration values.
    • If topic or broker settings can’t be fetched, the app now logs a warning and continues using a safe fallback instead of failing outright.
    • Validation of minimum in-sync replicas is now less likely to block progress when configuration lookup errors occur, while still reporting invalid values.

Signed-off-by: wk989898 <nhsmwk@gmail.com>
@ti-chi-bot

ti-chi-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot Bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Error handling in pkg/sink/kafka/options.go is relaxed for Kafka configuration lookups. Failures reading topic or broker max message bytes now log warnings and fall back to configured/default values instead of returning errors. Similarly, min.insync.replicas fetch errors are now treated as non-fatal, logging a warning and assuming valid configuration.

Changes

Kafka Configuration Fallback Handling

Layer / File(s) Summary
Fallback for max message bytes lookups
pkg/sink/kafka/options.go
When reading max.message.bytes from topic config or message.max.bytes from broker config fails, the function logs a warning and falls back to options.MaxMessageBytes instead of erroring; parse failures on retrieved values still return errors.
Fallback for min.insync.replicas validation
pkg/sink/kafka/options.go
validateMinInsyncReplicas now returns nil and logs a warning for any error fetching min.insync.replicas, not just config-not-found errors, assuming the config is valid.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit hops through Kafka's maze,
Where ACLs once blocked the ways,
Now warnings whisper, fallbacks flow,
No more errors, just "let it go" 🐰
Configs missing? No despair—
Defaults step in with gentle care.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes align with #5563 by using option defaults when Kafka config access fails while still erroring on invalid values.
Out of Scope Changes check ✅ Passed The PR only touches Kafka option handling and related behavior, with no clear unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title matches the Kafka ACL fallback change, though the wording is awkward.
Description check ✅ Passed The description includes the issue number, change summary, tests, and release note; only the question prompts are left blank.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ti-chi-bot ti-chi-bot Bot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Jul 3, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces fallback mechanisms in pkg/sink/kafka/options.go when retrieving Kafka configurations (such as max.message.bytes and message.max.bytes) fails, falling back to options.MaxMessageBytes instead of returning an error. It also updates validateMinInsyncReplicas to log a warning and assume validity if retrieving min.insync.replicas fails. However, the reviewer identified critical bugs in the fallback implementations: if retrieving the configuration fails, the code still attempts to parse the uninitialized configuration string using strconv.Atoi, which will fail and return an error anyway. The reviewer provided code suggestions to wrap the parsing logic in else blocks to ensure the fallback values are correctly used.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread pkg/sink/kafka/options.go
Comment on lines +610 to 619
var topicMaxMessageBytes int
if err != nil {
return errors.Trace(err)
log.Warn("TiCDC cannot find `max.message.bytes` from topic's configuration, use the option `MaxMessageBytes` as default")
topicMaxMessageBytes = options.MaxMessageBytes
// return errors.Trace(err)
}
topicMaxMessageBytes, err := strconv.Atoi(topicMaxMessageBytesStr)
topicMaxMessageBytes, err = strconv.Atoi(topicMaxMessageBytesStr)
if err != nil {
return errors.Trace(err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

If getTopicConfig fails, err is not nil, and we set topicMaxMessageBytes = options.MaxMessageBytes. However, the code immediately proceeds to execute strconv.Atoi(topicMaxMessageBytesStr). Since topicMaxMessageBytesStr is empty or invalid, strconv.Atoi will fail and return an error, which is then returned by the function. This completely defeats the fallback mechanism. We should only parse topicMaxMessageBytesStr when getTopicConfig succeeds.

Suggested change
var topicMaxMessageBytes int
if err != nil {
return errors.Trace(err)
log.Warn("TiCDC cannot find `max.message.bytes` from topic's configuration, use the option `MaxMessageBytes` as default")
topicMaxMessageBytes = options.MaxMessageBytes
// return errors.Trace(err)
}
topicMaxMessageBytes, err := strconv.Atoi(topicMaxMessageBytesStr)
topicMaxMessageBytes, err = strconv.Atoi(topicMaxMessageBytesStr)
if err != nil {
return errors.Trace(err)
}
var topicMaxMessageBytes int
if err != nil {
log.Warn("TiCDC cannot find `max.message.bytes` from topic's configuration, use the option `MaxMessageBytes` as default")
topicMaxMessageBytes = options.MaxMessageBytes
} else {
topicMaxMessageBytes, err = strconv.Atoi(topicMaxMessageBytesStr)
if err != nil {
return errors.Trace(err)
}
}

Comment thread pkg/sink/kafka/options.go
Comment on lines +649 to 658
var brokerMessageMaxBytes int
brokerMessageMaxBytesStr, err := admin.GetBrokerConfig(BrokerMessageMaxBytesConfigName)
if err != nil {
log.Warn("TiCDC cannot find `message.max.bytes` from broker's configuration")
return errors.Trace(err)
log.Warn("TiCDC cannot find `message.max.bytes` from broker's configuration, use the option `MaxMessageBytes` as default")
brokerMessageMaxBytes = options.MaxMessageBytes
}
brokerMessageMaxBytes, err := strconv.Atoi(brokerMessageMaxBytesStr)
brokerMessageMaxBytes, err = strconv.Atoi(brokerMessageMaxBytesStr)
if err != nil {
return errors.Trace(err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

If admin.GetBrokerConfig fails, err is not nil, and we set brokerMessageMaxBytes = options.MaxMessageBytes. However, the code immediately proceeds to execute strconv.Atoi(brokerMessageMaxBytesStr). Since brokerMessageMaxBytesStr is empty or invalid, strconv.Atoi will fail and return an error, which is then returned by the function. This completely defeats the fallback mechanism. We should only parse brokerMessageMaxBytesStr when admin.GetBrokerConfig succeeds.

Suggested change
var brokerMessageMaxBytes int
brokerMessageMaxBytesStr, err := admin.GetBrokerConfig(BrokerMessageMaxBytesConfigName)
if err != nil {
log.Warn("TiCDC cannot find `message.max.bytes` from broker's configuration")
return errors.Trace(err)
log.Warn("TiCDC cannot find `message.max.bytes` from broker's configuration, use the option `MaxMessageBytes` as default")
brokerMessageMaxBytes = options.MaxMessageBytes
}
brokerMessageMaxBytes, err := strconv.Atoi(brokerMessageMaxBytesStr)
brokerMessageMaxBytes, err = strconv.Atoi(brokerMessageMaxBytesStr)
if err != nil {
return errors.Trace(err)
}
var brokerMessageMaxBytes int
brokerMessageMaxBytesStr, err := admin.GetBrokerConfig(BrokerMessageMaxBytesConfigName)
if err != nil {
log.Warn("TiCDC cannot find `message.max.bytes` from broker's configuration, use the option `MaxMessageBytes` as default")
brokerMessageMaxBytes = options.MaxMessageBytes
} else {
brokerMessageMaxBytes, err = strconv.Atoi(brokerMessageMaxBytesStr)
if err != nil {
return errors.Trace(err)
}
}

Signed-off-by: wk989898 <nhsmwk@gmail.com>
@ti-chi-bot ti-chi-bot Bot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Jul 3, 2026
@wk989898 wk989898 marked this pull request as ready for review July 6, 2026 07:35
@ti-chi-bot ti-chi-bot Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 6, 2026
@ti-chi-bot ti-chi-bot Bot added needs-1-more-lgtm Indicates a PR needs 1 more LGTM. approved labels Jul 6, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: asddongmen, lidezhu

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jul 6, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-07-06 07:39:26.907714025 +0000 UTC m=+8152.943809071: ☑️ agreed by lidezhu.
  • 2026-07-06 07:40:22.597884024 +0000 UTC m=+8208.633979110: ☑️ agreed by asddongmen.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pkg/sink/kafka/options.go (2)

610-633: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fallback value self-triggers spurious overhead subtraction.

When getTopicConfig fails entirely, topicMaxMessageBytes is set equal to options.MaxMessageBytes (Line 613). That equal value then flows into the unchanged comparison at Line 622 (topicMaxMessageBytes <= options.MaxMessageBytes), which is trivially true on equality, causing Line 628 to execute options.MaxMessageBytes = topicMaxMessageBytes - maxMessageBytesOverhead. The net effect: every time this fallback triggers, the user's configured MaxMessageBytes is silently shrunk by 128 bytes for no real reason, and the emitted warning at Line 623-627 misleadingly claims the topic's actual max.message.bytes is smaller than the configured option, even though no real topic data was obtained.

This undermines the fallback's intent of "keep using the option value as-is" — it should leave options.MaxMessageBytes untouched when the fallback path is taken.

🐛 Proposed fix to skip the overhead adjustment on fallback
 		var topicMaxMessageBytes int
+		usedFallback := false
 		if err != nil {
 			log.Warn("TiCDC cannot find `max.message.bytes` from topic's configuration, use the option `MaxMessageBytes` as default")
 			topicMaxMessageBytes = options.MaxMessageBytes
+			usedFallback = true
 		} else {
 			topicMaxMessageBytes, err = strconv.Atoi(topicMaxMessageBytesStr)
 			if err != nil {
 				return errors.Trace(err)
 			}
 		}

-		maxMessageBytes := topicMaxMessageBytes - maxMessageBytesOverhead
-		if topicMaxMessageBytes <= options.MaxMessageBytes {
-			log.Warn("topic's `max.message.bytes` less than the `max-message-bytes`,"+
-				"use topic's `max.message.bytes` to initialize the Kafka producer",
-				zap.Int("max.message.bytes", topicMaxMessageBytes),
-				zap.Int("max-message-bytes", options.MaxMessageBytes),
-				zap.Int("real-max-message-bytes", maxMessageBytes))
-			options.MaxMessageBytes = maxMessageBytes
-		} else {
-			if maxMessageBytes < options.MaxMessageBytes {
-				options.MaxMessageBytes = maxMessageBytes
+		if !usedFallback {
+			maxMessageBytes := topicMaxMessageBytes - maxMessageBytesOverhead
+			if topicMaxMessageBytes <= options.MaxMessageBytes {
+				log.Warn("topic's `max.message.bytes` less than the `max-message-bytes`,"+
+					"use topic's `max.message.bytes` to initialize the Kafka producer",
+					zap.Int("max.message.bytes", topicMaxMessageBytes),
+					zap.Int("max-message-bytes", options.MaxMessageBytes),
+					zap.Int("real-max-message-bytes", maxMessageBytes))
+				options.MaxMessageBytes = maxMessageBytes
+			} else {
+				if maxMessageBytes < options.MaxMessageBytes {
+					options.MaxMessageBytes = maxMessageBytes
+				}
 			}
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/sink/kafka/options.go` around lines 610 - 633, The fallback path in the
Kafka topic config handling is incorrectly treated like a real topic value, so
`options.MaxMessageBytes` gets reduced by `maxMessageBytesOverhead` even when
`getTopicConfig` fails. Update the logic in the `options.go` flow around
`topicMaxMessageBytes` so the defaulting branch that uses
`options.MaxMessageBytes` bypasses the `topicMaxMessageBytes <=
options.MaxMessageBytes` comparison and the subsequent overwrite, leaving the
configured `MaxMessageBytes` unchanged when no topic config is available.

649-677: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Same self-triggering overhead-reduction bug on the broker fallback path.

Identical pattern to the topic-config fallback: on lookup failure brokerMessageMaxBytes is set to options.MaxMessageBytes (Line 653), which then makes the unchanged Line 666 (brokerMessageMaxBytes <= options.MaxMessageBytes) trivially true, shrinking options.MaxMessageBytes by maxMessageBytesOverhead and logging a misleading "broker's message.max.bytes less than max-message-bytes" warning based on fabricated equal values rather than real broker data.

🐛 Proposed fix mirroring the topic-side fix
 	var brokerMessageMaxBytes int
+	usedFallback := false
 	brokerMessageMaxBytesStr, err := admin.GetBrokerConfig(BrokerMessageMaxBytesConfigName)
 	if err != nil {
 		log.Warn("TiCDC cannot find `message.max.bytes` from broker's configuration, use the option `MaxMessageBytes` as default")
 		brokerMessageMaxBytes = options.MaxMessageBytes
+		usedFallback = true
 	} else {
 		brokerMessageMaxBytes, err = strconv.Atoi(brokerMessageMaxBytesStr)
 		if err != nil {
 			return errors.Trace(err)
 		}
 	}

-	maxMessageBytes := brokerMessageMaxBytes - maxMessageBytesOverhead
-	if brokerMessageMaxBytes <= options.MaxMessageBytes {
-		...
-		options.MaxMessageBytes = maxMessageBytes
-	} else {
-		if maxMessageBytes < options.MaxMessageBytes {
-			options.MaxMessageBytes = maxMessageBytes
+	if !usedFallback {
+		maxMessageBytes := brokerMessageMaxBytes - maxMessageBytesOverhead
+		if brokerMessageMaxBytes <= options.MaxMessageBytes {
+			...
+			options.MaxMessageBytes = maxMessageBytes
+		} else {
+			if maxMessageBytes < options.MaxMessageBytes {
+				options.MaxMessageBytes = maxMessageBytes
+			}
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/sink/kafka/options.go` around lines 649 - 677, In the broker fallback
path in options.go, the current use of options.MaxMessageBytes as the default
for brokerMessageMaxBytes causes the later comparison in the MaxMessageBytes
adjustment block to self-trigger and incorrectly shrink the producer limit.
Update the GetBrokerConfig fallback in the brokerMessageMaxBytes handling so it
does not feed a fabricated value into the comparison; instead preserve a
separate fallback state or skip the broker-based override when the broker config
lookup fails, matching the topic-config fix. Keep the logic in the
MaxMessageBytes adjustment section and the warning around broker's
message.max.bytes consistent with the real broker value, using the existing
symbols BrokerMessageMaxBytesConfigName, brokerMessageMaxBytes, and
options.MaxMessageBytes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/sink/kafka/options.go`:
- Around line 610-633: The fallback path in the Kafka topic config handling is
incorrectly treated like a real topic value, so `options.MaxMessageBytes` gets
reduced by `maxMessageBytesOverhead` even when `getTopicConfig` fails. Update
the logic in the `options.go` flow around `topicMaxMessageBytes` so the
defaulting branch that uses `options.MaxMessageBytes` bypasses the
`topicMaxMessageBytes <= options.MaxMessageBytes` comparison and the subsequent
overwrite, leaving the configured `MaxMessageBytes` unchanged when no topic
config is available.
- Around line 649-677: In the broker fallback path in options.go, the current
use of options.MaxMessageBytes as the default for brokerMessageMaxBytes causes
the later comparison in the MaxMessageBytes adjustment block to self-trigger and
incorrectly shrink the producer limit. Update the GetBrokerConfig fallback in
the brokerMessageMaxBytes handling so it does not feed a fabricated value into
the comparison; instead preserve a separate fallback state or skip the
broker-based override when the broker config lookup fails, matching the
topic-config fix. Keep the logic in the MaxMessageBytes adjustment section and
the warning around broker's message.max.bytes consistent with the real broker
value, using the existing symbols BrokerMessageMaxBytesConfigName,
brokerMessageMaxBytes, and options.MaxMessageBytes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3689eaaf-d98e-4ef8-9878-d8b3a18ef730

📥 Commits

Reviewing files that changed from the base of the PR and between d2da619 and 1ca6269.

📒 Files selected for processing (1)
  • pkg/sink/kafka/options.go

@ti-chi-bot ti-chi-bot Bot merged commit 2258270 into pingcap:master Jul 6, 2026
30 of 31 checks passed
@wk989898

wk989898 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

/cherry-pick release-nextgen-202603

@ti-chi-bot

Copy link
Copy Markdown
Member

@wk989898: new pull request created to branch release-nextgen-202603: #5591.

Details

In response to this:

/cherry-pick release-nextgen-202603

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository.

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

Labels

approved lgtm release-note Denotes a PR that will be considered when it comes time to generate release notes. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kafka meets authorization and acl failed

4 participants