Skip to content

fix(stringutil): operate on runes instead of bytes in Truncate (#22388)#22467

Merged
johnstcn merged 1 commit intorelease/2.30from
cj/r230/stringutil-fix
Mar 2, 2026
Merged

fix(stringutil): operate on runes instead of bytes in Truncate (#22388)#22467
johnstcn merged 1 commit intorelease/2.30from
cj/r230/stringutil-fix

Conversation

@johnstcn
Copy link
Member

@johnstcn johnstcn commented Mar 2, 2026

Fixes #22375

Updates stringutil.Truncate to properly handle multi-byte UTF-8 characters.
Adds tests for multi-byte truncation with word boundary.

Created by Mux using Opus 4.6

(cherry picked from commit 0cfa037)

Fixes #22375

Updates `stringutil.Truncate` to properly handle multi-byte UTF-8
characters.
Adds tests for multi-byte truncation with word boundary.

Created by Mux using Opus 4.6

(cherry picked from commit 0cfa037)
@johnstcn johnstcn self-assigned this Mar 2, 2026
@johnstcn johnstcn added the cherry-pick/v2.30 Needs to be cherry-picked to the 2.30 release branch label Mar 2, 2026
@johnstcn johnstcn marked this pull request as ready for review March 2, 2026 10:56
@johnstcn johnstcn requested review from Copilot, f0ssel and matifali March 2, 2026 10:56
@coder-tasks
Copy link
Contributor

coder-tasks bot commented Mar 2, 2026

Documentation Check

No Changes Needed

This PR is a purely internal bug fix — it corrects multi-byte UTF-8 handling in stringutil.Truncate and adds an internal Capitalize helper. All changes are confined to internal utility packages (coderd/util/strings, coderd/taskname) with no user-facing API, CLI, or configuration impact.


Automated review via Coder Tasks

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug where stringutil.Truncate was operating on byte indices rather than rune (Unicode code point) counts, causing multi-byte UTF-8 characters (e.g. em dash , CJK characters, emoji) to be split at truncation boundaries, producing invalid byte sequences that PostgreSQL rejects. It also introduces a safe Capitalize utility to replace raw s[:1] byte-slicing for capitalizing display names.

Changes:

  • Truncate now converts the string to a []rune slice and counts/slices by rune index instead of byte index, making it safe for all valid UTF-8 inputs.
  • A new Capitalize(s string) string helper is introduced in strutil, using utf8.DecodeRuneInString to safely upper-case the first rune of a string.
  • Both generateFromPrompt and generateFromAnthropic in taskname.go are updated to use strutil.Capitalize instead of the unsafe strings.ToUpper(s[:1]) + s[1:] pattern.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
coderd/util/strings/strings.go Core fix: Truncate now works on rune slices; new Capitalize helper added
coderd/util/strings/strings_test.go Tests for multi-byte truncation (CJK, emoji, mixed) and new TestCapitalize
coderd/taskname/taskname.go generateFromPrompt and generateFromAnthropic now use strutil.Capitalize
coderd/taskname/taskname_test.go New FromPromptMultiByte test exercising multi-byte capitalize path

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

taskName := taskname.Generate(ctx, testutil.Logger(t), "über cool feature")

require.NoError(t, codersdk.NameValid(taskName.Name))
require.True(t, len(taskName.DisplayName) > 0)
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The require.True(t, len(taskName.DisplayName) > 0) assertion on this line is redundant, since the require.Equal(t, "Über cool feature", taskName.DisplayName) assertion on the next line already implies the display name is non-empty. The require.True check provides no additional safety and can be removed to keep the test clean and avoid misleading readers about the test's purpose.

Suggested change
require.True(t, len(taskName.DisplayName) > 0)

Copilot uses AI. Check for mistakes.
@johnstcn johnstcn merged commit 7e0cf53 into release/2.30 Mar 2, 2026
37 checks passed
@johnstcn johnstcn deleted the cj/r230/stringutil-fix branch March 2, 2026 11:19
@github-actions github-actions bot locked and limited conversation to collaborators Mar 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cherry-pick/v2.30 Needs to be cherry-picked to the 2.30 release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants