Skip to content

fix: decode only percent-encoded escapes in decodeURIComponent - #25672

Merged
Artur- merged 4 commits into
mainfrom
fix/decode-uri-component-keeps-literal-non-ascii
Sep 14, 2026
Merged

Artur- merged 4 commits into
mainfrom
fix/decode-uri-component-keeps-literal-non-ascii

Conversation

@totally-not-ai

@totally-not-ai totally-not-ai Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

UrlUtil.decodeURIComponent treated every non-ASCII character as a raw UTF-8 byte, even when it was never percent-encoded. Because of that, paths that already contain literal characters like ü or 日 were corrupted into �, so routes with non-ASCII segments did not match and wildcard parameters lost their text. Now only real %XX escapes are decoded and all other characters are left untouched.

What changed

Behavior change: UrlUtil.decodeURIComponent no longer rewrites non-ASCII characters that are not percent-encoded. This affects anyone who passes an already decoded (or partly decoded) string: before it came back mangled, now it comes back unchanged. Strings that only contain %XX escapes decode exactly as before, so normal encoded input is unaffected.

  • decodeURIComponent now collects consecutive %XX escapes into a byte sequence and decodes that sequence as UTF-8. Text between escapes is copied as-is, so a multi-byte character split over several escapes still decodes to one character.
  • Input without any escape is returned directly.
  • Javadoc now states that unescaped characters are kept as they are.

Why this matters in practice: a servlet container decodes the path info, so the first server-side navigation sees literal characters. Static route segments with a non-ASCII character never matched, and @WildcardParameter values were corrupted. Jar URLs are also not required to be percent-encoded, so ResourceFolderUtil silently found no resources in a folder whose entry name contains a non-ASCII character.

No public or protected API was added, removed, or changed.

Fixes #25671

Test summary

# Status What the test verifies Why it matters
1 ✅ A string with literal non-ASCII characters (grüße, 日本, an emoji) is returned unchanged This is the bug: such input used to become �
2 ✅ A string mixing %XX escapes and literal characters decodes to grüße-ü-äxö Both forms must work in the same string; also pins that multi-byte escapes still decode
3 ✅ A static route grüße matches both the literal and the percent-encoded location Server-side navigation sees literal text, client-side sees encoded text
4 ✅ A @WildcardParameter value keeps grüße for literal input and decodes it for encoded input Corrupted parameter values were the visible symptom for apps
5 ✅ PathUtil.getSegmentsListWithDecoding keeps literal UTF-8 segments and splits them correctly Route resolution is built on this splitting step
6 ✅ ResourceFolderUtil.visitFiles finds files in a jar folder named thèmes/ Resources in such folders were silently skipped
7 ❗ gap Behaviour for a malformed or truncated escape (for example a lone %C3) Invalid input should degrade predictably, not throw
  • UrlUtilTest.decodeURIComponent_literalNonAsciiCharacters_returnedUnchanged → 1
  • UrlUtilTest.decodeURIComponent_literalAndEncodedNonAsciiCharacters_bothDecoded → 2
  • RouterTest.static_route_with_non_ascii_character → 3
  • RouterTest.wildcard_parameter_with_non_ascii_characters → 4
  • PathUtilTest.getSegmentsListWithDecoding_handlesUtf8Characters (extended) → 5
  • ResourceFolderUtilTest.folderPathContainsLiteralNonAsciiCharacter_filesInTheJarAreVisited → 6

Deliberately not tested: the new private appendDecoded helper, which is covered through the public method, and plain ASCII or %2F decoding, which existing tests in UrlUtilTest and PathUtilTest already pin.

UrlUtil.decodeURIComponent reassembled UTF-8 bytes from every character
with a code point above 127, including characters that were never
percent-encoded. A literal non-ASCII character was thus reinterpreted as
a UTF-8 byte and replaced with U+FFFD.

A servlet container decodes the path info, so the initial server side
navigation sees literal characters. Static route segments containing a
non-ASCII character therefore never matched, and @WildcardParameter
values were corrupted.

Percent-encoded escapes are now collected into a byte sequence that is
decoded as UTF-8, while the surrounding characters are kept as they are.

Fixes #25671
@github-actions

github-actions Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

 1 440 files  ±0   1 524 suites  ±0   1h 30m 15s ⏱️ - 4m 22s
12 065 tests +5  11 997 ✅ +5  68 💤 ±0  0 ❌ ±0 
12 383 runs  +5  12 315 ✅ +5  68 💤 ±0  0 ❌ ±0 

Results for commit 8e05bcc. ± Comparison against base commit 980ac5b.

♻️ This comment has been updated with latest results.

@Artur-

Artur- commented Sep 11, 2026 •

Copy link
Copy Markdown
Member

Isn't what truly is wrong here that a decoded string is passed to decodeURIComponent?

A jar URL does not have to be percent-encoded, so ResourceFolderUtil
reads folder entry names that have the characters they have in the jar.
The test fails without the decodeURIComponent fix, where the resources
of such a folder are silently not found.
@totally-not-ai

Copy link
Copy Markdown
Contributor Author

@Artur- Yes — and that is a better framing than the one in the issue. The double decode is the cause of the routing symptom; this PR only stops the second decode from destroying data. Worth splitting into two questions.

Is decodeURIComponent itself wrong? It is, independently of routing. It is documented as the equivalent of JavaScript's decodeURIComponent(), and it reassembled UTF-8 bytes from every char above 127, including chars that were never escaped — so a code point above U+00FF was also truncated by the (byte) cast (日本 → �,). It has callers that legitimately pass strings that were never percent-encoded: ResourceFolderUtil.getFolderEntryName decodes the entry part of a jar URL, and a jar URL does not have to be encoded. I pushed a test for that case — a jar with a thèmes/ folder finds zero resources on main and the files on this branch, with no routing involved. So this change stands on its own merit.

Is it the fix for the reported issue? No, it is a narrowing of it. Route resolution has three input sources with two conventions:

  • BootstrapHandler builds the Location from HttpServletRequest#getPathInfo(), which the container has already decoded → decoded.
  • Flow.ts sends window.location.pathname undecoded, both as the location init parameter and for client-side navigation → encoded (deliberately, since fix: preserve URL-encoded characters in wildcard route parameters #22791).
  • UI.navigate(String) and BeforeEvent.forwardTo(String) take whatever the application wrote, which in practice is human-readable → decoded.

PathUtil.getSegmentsListWithDecoding assumes the encoded convention, so the other two get decoded twice. This PR makes the second decode harmless for unescaped characters, but it is still wrong for literal text that looks like an escape: an already decoded 50%20off still becomes 50 off, so a route or wildcard value containing a literal percent is still corrupted.

Fixing that properly means picking one canonical form for the path that reaches the router, and both choices have consequences:

  1. Canonical encoded — build the bootstrap Location from the raw request URI instead of getPathInfo(), and require pre-encoded input from UI.navigate/forwardTo (as RouteConfiguration#getUrl already documents). Makes the eager page load agree with client-side navigation, which is encoded today. But it leaves UI.navigate("grüße") broken, and Location#getPath() starts returning percent-encoded text on the initial load, which applications can observe.
  2. Canonical decoded — decode exactly once, at the boundary where the encoded form is known, and never in the router. That is what applications want downstream, but it needs Location to carry the path as segments rather than one string, otherwise rejoining them loses the %2F distinction that fix: preserve URL-encoded characters in wildcard route parameters #22791 was about.

Either one changes Location semantics, so I did not put it in this PR. Which direction would you prefer? I am happy to do it here, or keep this as the narrow data-corruption fix (it is also the part that backports cleanly to 24.9) and open a separate issue for the contract.

@Artur-

Artur- commented Sep 12, 2026

Copy link
Copy Markdown
Member

Please create an issue about the cases where it is decoded even though it should not be, so that can be fixed separately.

@Artur-

Artur- commented Sep 12, 2026

Copy link
Copy Markdown
Member

@claude review and check that decodeURIComponent now works as in the browser

@claude

claude Bot commented Sep 12, 2026 •

Copy link
Copy Markdown

Claude finished @Artur-'s task in 3m 12s —— View job


Review: does decodeURIComponent now behave like the browser?

  • Read the new implementation
  • Compare against browser decodeURIComponent (valid + malformed input)
  • Check tests
  • Post review

Verdict: for every well‑formed input the browser can decode, this implementation now returns the identical result. The only divergence is error handling on malformed input, which is exactly the gap (#7) already called out in the PR description.

I verified this empirically rather than by reasoning: I ran each input through a real browser's decodeURIComponent() (via Playwright) and through the exact code from UrlUtil.java (line‑for‑line copy). Side by side:

Input Browser This PR Match
test%20file.txt test file.txt test file.txt ✅
test+file.txt test+file.txt test+file.txt ✅ (+ not treated as space, like the browser)
%C3%A5%C3%A4%C3%B6.txt åäö.txt åäö.txt ✅
grüße grüße grüße ✅ (the bug being fixed)
日本 日本 日本 ✅ (code point > U+00FF, was truncated before)
emoji 😀 emoji 😀 emoji 😀 ✅
gr%C3%BC%C3%9Fe-ü-%C3%A4x%C3%B6 grüße-ü-äxö grüße-ü-äxö ✅ (literal + encoded mixed)
%F0%9F%98%80 😀 😀 ✅ (4‑byte char across 4 escapes)
100%25 100% 100% ✅
%00 `` `` ✅
% throws URIError % ⚠️
%2 throws URIError %2 ⚠️
%zz throws URIError %zz ⚠️
%C3 throws URIError � ⚠️
%C3%28 throws URIError �( ⚠️
a%b%C3%BC throws URIError a%bü ⚠️
%ED%A0%80 (surrogate) throws URIError ��� ⚠️

What's correct

  • The core fix is right and well implemented. Collecting consecutive %XX escapes into one byte buffer and flushing it whenever a literal run interrupts (UrlUtil.java:178-191) is the correct way to keep multi‑byte UTF‑8 whole while never re‑interpreting literal characters as bytes. This is precisely what the old (byte) c cast got wrong for code points above U+00FF (日本 → �).
  • The early return encoded when there is no escape (UrlUtil.java:167-170) matches the browser's pass‑through of already‑decoded strings.
  • + is preserved rather than turned into a space, matching decodeURIComponent (and unlike URLDecoder) — confirmed above.

The one divergence — malformed input

The browser's decodeURIComponent throws URIError: URI malformed on every malformed escape; this method instead degrades gracefully (keeps the literal %xx text when the two hex digits are absent, or emits U+FFFD � when the bytes aren't valid UTF‑8, because ByteArrayOutputStream.toString(UTF_8) substitutes rather than throws).

For the internal routing / resource‑lookup use case this is arguably the better behaviour — you don't want a stray % in a path to blow up navigation with an exception — so I would not change the behaviour. But two small things are worth doing:

  1. Javadoc accuracy. The doc says it "Corresponds to decodeURIComponent in JavaScript" (UrlUtil.java:144-145). That's now true for valid input but not for malformed input, where the browser throws and this doesn't. A one‑line note ("malformed or incomplete escapes are left as‑is / replaced rather than throwing, unlike the browser") would make the contract honest. Fix this →
  2. Test the gap. Add a test pinning the malformed cases above (%, %2, %zz, %C3, %C3%28) so the graceful‑degradation contract is intentional and can't silently regress into throwing. Fix this →

Note on scope

This confirms what you and the author already discussed: the change is a sound, self‑contained data‑corruption fix and correctly aligns decodeURIComponent with the browser for valid input. The remaining double‑decode contract issue (e.g. a literal 50%20off still decoding to 50 off) is separate and, per your last comment, belongs in its own issue — it is not something this method can fix in isolation, since the caller passes an already‑decoded string.
· branch fix/decode-uri-component-keeps-literal-non-ascii

Records where the assumption is made, as the callers that pass a path
that is already decoded are fixed separately in #25690.
@sonarqubecloud

Copy link
Copy Markdown

@Artur-
Artur- added this pull request to the merge queue Sep 14, 2026
Merged via the queue into main with commit 9e407f9 Sep 14, 2026
44 checks passed
@Artur-
Artur- deleted the fix/decode-uri-component-keeps-literal-non-ascii branch September 14, 2026 10:45
vaadin-bot added a commit that referenced this pull request Sep 14, 2026
… (CP: 25.3) (#25703)

This PR cherry-picks changes from the original PR #25672 to branch 25.3.
---
#### Original PR description
> ## Summary
> `UrlUtil.decodeURIComponent` treated every non-ASCII character as a
raw UTF-8 byte, even when it was never percent-encoded. Because of that,
paths that already contain literal characters like `ü` or `日` were
corrupted into `�`, so routes with non-ASCII segments did not match and
wildcard parameters lost their text. Now only real `%XX` escapes are
decoded and all other characters are left untouched.
> 
> ## What changed
> **Behavior change:** `UrlUtil.decodeURIComponent` no longer rewrites
non-ASCII characters that are not percent-encoded. This affects anyone
who passes an already decoded (or partly decoded) string: before it came
back mangled, now it comes back unchanged. Strings that only contain
`%XX` escapes decode exactly as before, so normal encoded input is
unaffected.
> 
> - `decodeURIComponent` now collects consecutive `%XX` escapes into a
byte sequence and decodes that sequence as UTF-8. Text between escapes
is copied as-is, so a multi-byte character split over several escapes
still decodes to one character.
> - Input without any escape is returned directly.
> - Javadoc now states that unescaped characters are kept as they are.
> 
> Why this matters in practice: a servlet container decodes the path
info, so the first server-side navigation sees literal characters.
Static route segments with a non-ASCII character never matched, and
`@WildcardParameter` values were corrupted. Jar URLs are also not
required to be percent-encoded, so `ResourceFolderUtil` silently found
no resources in a folder whose entry name contains a non-ASCII
character.
> 
> No public or protected API was added, removed, or changed.
> 
> Fixes #25671
> 
> ## Test summary
> 
> | # | Status | What the test verifies | Why it matters |
> |---|--------|------------------------|----------------|
> | 1 | ✅ | A string with literal non-ASCII characters (`grüße`, `日本`,
an emoji) is returned unchanged | This is the bug: such input used to
become `�` |
> | 2 | ✅ | A string mixing `%XX` escapes and literal characters decodes
to `grüße-ü-äxö` | Both forms must work in the same string; also pins
that multi-byte escapes still decode |
> | 3 | ✅ | A static route `grüße` matches both the literal and the
percent-encoded location | Server-side navigation sees literal text,
client-side sees encoded text |
> | 4 | ✅ | A `@WildcardParameter` value keeps `grüße` for literal input
and decodes it for encoded input | Corrupted parameter values were the
visible symptom for apps |
> | 5 | ✅ | `PathUtil.getSegmentsListWithDecoding` keeps literal UTF-8
segments and splits them correctly | Route resolution is built on this
splitting step |
> | 6 | ✅ | `ResourceFolderUtil.visitFiles` finds files in a jar folder
named `thèmes/` | Resources in such folders were silently skipped |
> | 7 | ❗ **gap** | Behaviour for a malformed or truncated escape (for
example a lone `%C3`) | Invalid input should degrade predictably, not
throw |
> 
> -
`UrlUtilTest.decodeURIComponent_literalNonAsciiCharacters_returnedUnchanged`
→ 1
> -
`UrlUtilTest.decodeURIComponent_literalAndEncodedNonAsciiCharacters_bothDecoded`
→ 2
> - `RouterTest.static_route_with_non_ascii_character` → 3
> - `RouterTest.wildcard_parameter_with_non_ascii_characters` → 4
> - `PathUtilTest.getSegmentsListWithDecoding_handlesUtf8Characters`
(extended) → 5
> -
`ResourceFolderUtilTest.folderPathContainsLiteralNonAsciiCharacter_filesInTheJarAreVisited`
→ 6
> 
> Deliberately not tested: the new private `appendDecoded` helper, which
is covered through the public method, and plain ASCII or `%2F` decoding,
which existing tests in `UrlUtilTest` and `PathUtilTest` already pin.

Co-authored-by: totally-not-ai[bot] <290682512+totally-not-ai[bot]@users.noreply.github.com>
Co-authored-by: Artur Signell <artur@vaadin.com>
@StefanPenndorf

Copy link
Copy Markdown

@Artur- are there any plans to backport this one to 25.2 or even 24.10 ?

@Artur-

Artur- commented Sep 15, 2026

Copy link
Copy Markdown
Member

We can do that

@vaadin-bot

Copy link
Copy Markdown
Collaborator

Hi @totally-not-ai[bot] and @Artur-, when i performed cherry-pick to this commit to 25.2, i have encountered the following issue. Can you take a look and pick it manually?
Error Message:
Error: Command failed: git cherry-pick 9e407f9
error: could not apply 9e407f9... fix: decode only percent-encoded escapes in decodeURIComponent (#25672)
hint: After resolving the conflicts, mark them with
hint: "git add/rm ", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".

@vaadin-bot

Copy link
Copy Markdown
Collaborator

Hi @totally-not-ai[bot] and @Artur-, when i performed cherry-pick to this commit to 24.10, i have encountered the following issue. Can you take a look and pick it manually?
Error Message:
Error: Command failed: git cherry-pick 9e407f9
error: could not apply 9e407f9... fix: decode only percent-encoded escapes in decodeURIComponent (#25672)
hint: After resolving the conflicts, mark them with
hint: "git add/rm ", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".

@Artur-

Artur- commented Sep 15, 2026

Copy link
Copy Markdown
Member

@claude backport this to 25.2

@claude

claude Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

Claude finished @Artur-'s task in 8m 25s —— View job • claude/pr-25672-20260915-1723 • [Create PR ➔](https://github.com/vaadin/flow/compare/main...claude/pr-25672-20260915-1723?quick_pull=1&title=PR%20%2325672%3A%20Changes%20from%20Claude&body=This%20PR%20addresses%20pr%20%2325672%0A%0AGenerated%20with%20%5BClaude%20Code%5D(https%3A%2F%2Fclaude.ai%2Fcode)


Backport PR #25672 to 25.2 — done ✅

  • Fetch the 25.2 branch and locate the merge commit (9e407f9b57)
  • Base the backport branch on 25.2
  • Apply the change and resolve the conflict
  • Build & run the affected tests — 187 tests, 0 failures
  • Push the branch

Why the automatic cherry-pick failed: the original PR also added a test to ResourceFolderUtilTest, but neither ResourceFolderUtil nor its test exists on 25.2 (that class was introduced by a separate change that was never backported — git grep visitFiles origin/25.2 finds nothing). I applied the fix by hand onto 25.2 and dropped only the ResourceFolderUtilTest addition, which has no target there.

What was backported (5 of the 6 files):

  • UrlUtil.java — the core fix: collect consecutive %XX escapes into a byte buffer decoded as UTF-8, copy literal text as-is, return early when nothing is escaped, plus the new appendDecoded helper and Javadoc note.
  • PathUtil.java — the double-decode Javadoc note.
  • UrlUtilTest, PathUtilTest, RouterTest — tests 1, 2, 3, 4, 5 from the PR's table.

All three affected test classes pass:

PathUtilTest  Tests run: 14,  Failures: 0, Errors: 0
RouterTest    Tests run: 138, Failures: 0, Errors: 0
UrlUtilTest   Tests run: 35,  Failures: 0, Errors: 0

mvn spotless:apply produced no changes.

Create the backport PR →

⚠️ The PR base is preset to 25.2 (not main) since this is a backport — please keep it that way when opening the PR.
· branch claude/pr-25672-20260915-1723

Artur- added a commit that referenced this pull request Sep 16, 2026
… (CP: 25.2) (#25735)

UrlUtil.decodeURIComponent treated every non-ASCII character as a raw
UTF-8 byte, even when it was never percent-encoded, so paths that
already contain literal characters like ü or 日 were corrupted into the
replacement character. Now only real %XX escapes are decoded and all
other characters are left untouched.

Backport of #25672 to 25.2. The ResourceFolderUtilTest case from the
original PR is omitted because ResourceFolderUtil does not exist on
25.2.

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Artur Signell <260340+Artur-@users.noreply.github.com>
@vaadin-bot

Copy link
Copy Markdown
Collaborator

This ticket/PR has been released with Vaadin 25.4.0-alpha1.

@mcollovati

Copy link
Copy Markdown
Collaborator

Picked into 25.2 by #25735

@totally-not-ai

totally-not-ai Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

This PR has been cherry-picked to 24.10: #26102

mcollovati pushed a commit that referenced this pull request Oct 1, 2026
… (CP: 24.10) (#26102)

This PR cherry-picks changes from the original PR #25672 to branch
24.10.
---
#### Original PR description
> ## Summary
> `UrlUtil.decodeURIComponent` treated every non-ASCII character as a
raw UTF-8 byte, even when it was never percent-encoded. Because of that,
paths that already contain literal characters like `ü` or `日` were
corrupted into `�`, so routes with non-ASCII segments did not match and
wildcard parameters lost their text. Now only real `%XX` escapes are
decoded and all other characters are left untouched.
> 
> ## What changed
> **Behavior change:** `UrlUtil.decodeURIComponent` no longer rewrites
non-ASCII characters that are not percent-encoded. This affects anyone
who passes an already decoded (or partly decoded) string: before it came
back mangled, now it comes back unchanged. Strings that only contain
`%XX` escapes decode exactly as before, so normal encoded input is
unaffected.
> 
> - `decodeURIComponent` now collects consecutive `%XX` escapes into a
byte sequence and decodes that sequence as UTF-8. Text between escapes
is copied as-is, so a multi-byte character split over several escapes
still decodes to one character.
> - Input without any escape is returned directly.
> - Javadoc now states that unescaped characters are kept as they are.
> 
> Why this matters in practice: a servlet container decodes the path
info, so the first server-side navigation sees literal characters.
Static route segments with a non-ASCII character never matched, and
`@WildcardParameter` values were corrupted. Jar URLs are also not
required to be percent-encoded, so `ResourceFolderUtil` silently found
no resources in a folder whose entry name contains a non-ASCII
character.
> 
> No public or protected API was added, removed, or changed.
> 
> Fixes #25671
> 
> ## Test summary
> 
> | # | Status | What the test verifies | Why it matters |
> |---|--------|------------------------|----------------|
> | 1 | ✅ | A string with literal non-ASCII characters (`grüße`, `日本`,
an emoji) is returned unchanged | This is the bug: such input used to
become `�` |
> | 2 | ✅ | A string mixing `%XX` escapes and literal characters decodes
to `grüße-ü-äxö` | Both forms must work in the same string; also pins
that multi-byte escapes still decode |
> | 3 | ✅ | A static route `grüße` matches both the literal and the
percent-encoded location | Server-side navigation sees literal text,
client-side sees encoded text |
> | 4 | ✅ | A `@WildcardParameter` value keeps `grüße` for literal input
and decodes it for encoded input | Corrupted parameter values were the
visible symptom for apps |
> | 5 | ✅ | `PathUtil.getSegmentsListWithDecoding` keeps literal UTF-8
segments and splits them correctly | Route resolution is built on this
splitting step |
> | 6 | ✅ | `ResourceFolderUtil.visitFiles` finds files in a jar folder
named `thèmes/` | Resources in such folders were silently skipped |
> | 7 | ❗ **gap** | Behaviour for a malformed or truncated escape (for
example a lone `%C3`) | Invalid input should degrade predictably, not
throw |
> 
> -
`UrlUtilTest.decodeURIComponent_literalNonAsciiCharacters_returnedUnchanged`
→ 1
> -
`UrlUtilTest.decodeURIComponent_literalAndEncodedNonAsciiCharacters_bothDecoded`
→ 2
> - `RouterTest.static_route_with_non_ascii_character` → 3
> - `RouterTest.wildcard_parameter_with_non_ascii_characters` → 4
> - `PathUtilTest.getSegmentsListWithDecoding_handlesUtf8Characters`
(extended) → 5
> -
`ResourceFolderUtilTest.folderPathContainsLiteralNonAsciiCharacter_filesInTheJarAreVisited`
→ 6
> 
> Deliberately not tested: the new private `appendDecoded` helper, which
is covered through the public method, and plain ASCII or `%2F` decoding,
which existing tests in `UrlUtilTest` and `PathUtilTest` already pin.

Co-authored-by: totally-not-ai[bot] <290682512+totally-not-ai[bot]@users.noreply.github.com>
Co-authored-by: Artur Signell <artur@vaadin.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Static route segments containing a literal non-ASCII character never match

4 participants