Regression: Nexus Repository trips over caret (^) in RPM names
We use nexus to proxy fedora 41 repositories. I can't say exactly with which version this error was introduced, however I can confirm that on version 3.83.1-CE this happens when trying to download a package with the caret "^" character in the URL using curl:
~$ curl https://mirrors.nexus.hdpgmbh.de/repository/fedora-41-x86_64-updates/Packages/p/passt-0^20250805.g309eefd-2.fc41.x86_64.rpm
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 400 Illegal Path Character</title>
</head>
<body>
<h2>HTTP ERROR 400 Illegal Path Character</h2>
<table>
<tr><th>URI:</th><td>/badURI</td></tr>
<tr><th>STATUS:</th><td>400</td></tr>
<tr><th>MESSAGE:</th><td>Illegal Path Character</td></tr>
</table>
<hr/><a href="https://jetty.org/">Powered by Jetty:// 12.0.17</a><hr/>
</body>
</html>
dnf update passt -y throws this error message:
Updating and loading repositories:
Repositories loaded.
Package Arch Version Repository Size
Upgrading:
passt x86_64 0^20250805.g309eefd-2.fc41 fedora-updates 1.2 MiB
replacing passt x86_64 0^20250606.g754c6d7-1.fc41 fedora-updates 1.2 MiB
passt-selinux noarch 0^20250805.g309eefd-2.fc41 fedora-updates 291.5 KiB
replacing passt-selinux noarch 0^20250606.g754c6d7-1.fc41 fedora-updates 289.9 KiB
Transaction Summary:
Upgrading: 2 packages
Replacing: 2 packages
Total size of inbound packages is 304 KiB. Need to download 304 KiB.
After this operation, 2 KiB extra will be used (install 1 MiB, remove 1 MiB).
Is this ok [y/N]: y
[1/2] passt-0:0^20250805.g309eefd-2.fc41.x86_64 100% | 13.8 KiB/s | 437.0 B | 00m00s
>>> Status code: 400 for https://mirrors.nexus.hdpgmbh.de/repository/fedora-41-x86_64-updates/Packages/p/passt-0^20250805.g309eefd-2.fc41.x86_64.rpm (IP: 192.168.54.12) - https://mirrors.nexus.hdpgmbh.de/reposito
>>> Status code: 400 for https://mirrors.nexus.hdpgmbh.de/repository/fedora-41-x86_64-updates/Packages/p/passt-0^20250805.g309eefd-2.fc41.x86_64.rpm (IP: 192.168.54.12) - https://mirrors.nexus.hdpgmbh.de/reposito
>>> No more mirrors to try - All mirrors were already tried without success
[2/2] passt-selinux-0:0^20250805.g309eefd-2.fc41.noarch 0% | 0.0 B/s | 0.0 B | 00m00s
>>> Status code: 400 for https://mirrors.nexus.hdpgmbh.de/repository/fedora-41-x86_64-updates/Packages/p/passt-selinux-0^20250805.g309eefd-2.fc41.noarch.rpm (IP: 192.168.54.12) - https://mirrors.nexus.hdpgmbh.de/
>>> Status code: 400 for https://mirrors.nexus.hdpgmbh.de/repository/fedora-41-x86_64-updates/Packages/p/passt-selinux-0^20250805.g309eefd-2.fc41.noarch.rpm (IP: 192.168.54.12) - https://mirrors.nexus.hdpgmbh.de/
>>> Not finished - interrupted by error: Cannot download Packages/p/passt-0^20250805.g309eefd-2.fc41.x86_64.rpm: All mirrors were tried
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[2/2] Total 100% | 12.2 KiB/s | 437.0 B | 00m00s
Failed to download packages
Librepo error: Cannot download Packages/p/passt-0^20250805.g309eefd-2.fc41.x86_64.rpm: All mirrors were tried
I have confirmed that dnf update passt -y completes without error using the fedora repos directly.
This problem has appeared before and was reported in: See: https://web.archive.org/web/20221126152259/https://issues.sonatype.org/browse/NEXUS-27899
It was actually fixed in 3.55.0: https://help.sonatype.com/en/sonatype-nexus-repository-3-55-0-release-notes.html#bug-fixes-161899
This issue is quite annoying since it stops the whole dnf update routine. Please, look into it. Sonatype Nexus v.3.85.0-03
YUM Proxy repository (Fedora Linux).
Packages (passt-0^20250919.g623dbf6-1.fc42.x86_64.rpm, passt-selinux-0:0^20250919.g623dbf6-1.fc42.noarch)with names containing "U+1F891 Upwards Triangle Arrowhead (^)" causing EoFException error. This results in update routine failure (dnf update):
$ sudo dnf update --refresh -y
Updating and loading repositories:
Fedora 42 - x86_64 - Updates 100% | 257.3 KiB/s | 5.4 KiB | 00m00s
Fedora 42 - x86_64 100% | 206.1 KiB/s | 4.3 KiB | 00m00s
Repositories loaded.
Package Arch Version Repository Size
Upgrading:
passt x86_64 0^20250919.g623dbf6-1.fc42 updates-nexus 1.2 MiB
replacing passt x86_64 0^20250611.g0293c6f-1.fc42 updates 1.1 MiB
passt-selinux noarch 0^20250919.g623dbf6-1.fc42 updates-nexus 293.0 KiB
replacing passt-selinux noarch 0^20250611.g0293c6f-1.fc42 updates 289.9 KiB
Transaction Summary:
Upgrading: 2 packages
Replacing: 2 packages
Total size of inbound packages is 309 KiB. Need to download 309 KiB.
After this operation, 44 KiB extra will be used (install 1 MiB, remove 1 MiB).
[1/2] passt-selinux-0:0^20250919.g623dbf6-1.fc42.noarch 100% | 24.7 KiB/s | 404.0 B | 00m00s
>>> Status code: 400 for https://<fqdn_replaced>/repository/fedora/linux/updates/42/Everything/x86_64/Packages/p/passt-selinux-0^20250919.g623dbf6-1.fc42.noarch.rpm (IP: 10.2.15.118) - htt
>>> Status code: 400 for https://<fqdn_replaced>/repository/fedora/linux/updates/42/Everything/x86_64/Packages/p/passt-selinux-0^20250919.g623dbf6-1.fc42.noarch.rpm (IP: 10.2.15.118) - htt
>>> No more mirrors to try - All mirrors were already tried without success
[2/2] passt-0:0^20250919.g623dbf6-1.fc42.x86_64 0% | 0.0 B/s | 0.0 B | 00m00s
>>> Status code: 400 for https://<fqdn_replaced>/repository/fedora/linux/updates/42/Everything/x86_64/Packages/p/passt-0^20250919.g623dbf6-1.fc42.x86_64.rpm (IP: 10.2.15.118) - https://nex
>>> Status code: 400 for https://<fqdn_replaced>/repository/fedora/linux/updates/42/Everything/x86_64/Packages/p/passt-0^20250919.g623dbf6-1.fc42.x86_64.rpm (IP: 10.2.15.118) - https://nex
>>> Not finished - interrupted by error: Cannot download Packages/p/passt-selinux-0^20250919.g623dbf6-1.fc42.noarch.rpm: All mirrors were tried
Relevant Nexus log entries:
2025-10-17 06:48:48,256+0000 WARN [qtp1278083126-1567] *UNKNOWN org.sonatype.nexus.repository.httpbridge.internal.ViewServlet - Failure servicing: GET /repository/fedora/linux/updates/42/Everything/x86_64/Packages/n/nvidia-gpu-firmware-20250917-2.fc42.noarch.rpm
org.eclipse.jetty.io.EofException: null
at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:118)
at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:422)
at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:275)
at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:254)
at org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:368)
at org.eclipse.jetty.server.internal.HttpConnection$SendCallback.process(HttpConnection.java:859)
at org.eclipse.jetty.util.IteratingCallback.processing(IteratingCallback.java:262)
at org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:243)
at org.eclipse.jetty.server.internal.HttpConnection$HttpStreamOverHTTP1.send(HttpConnection.java:1440)
at org.eclipse.jetty.server.HttpStream$Wrapper.send(HttpStream.java:185)
at org.eclipse.jetty.server.HttpStream$Wrapper.send(HttpStream.java:185)
at org.eclipse.jetty.ee8.nested.SessionHandler$SessionStreamWrapper.send(SessionHandler.java:113)
at org.eclipse.jetty.server.internal.HttpChannelState$ChannelResponse.write(HttpChannelState.java:1345)
at org.eclipse.jetty.server.Response$Wrapper.write(Response.java:813)
at org.eclipse.jetty.server.handler.ContextResponse.write(ContextResponse.java:56)
at org.eclipse.jetty.ee8.nested.HttpChannel.send(HttpChannel.java:835)
at org.eclipse.jetty.ee8.nested.HttpChannel.sendResponse(HttpChannel.java:822)
at org.eclipse.jetty.ee8.nested.HttpChannel.write(HttpChannel.java:889)
at org.eclipse.jetty.ee8.nested.HttpOutput.channelWrite(HttpOutput.java:294)
at org.eclipse.jetty.ee8.nested.HttpOutput.channelWrite(HttpOutput.java:281)
at org.eclipse.jetty.ee8.nested.HttpOutput.write(HttpOutput.java:753)
at com.sonatype.analytics.internal.filter.CountingServletOutputStream.write(CountingServletOutputStream.java:35)
at com.google.common.io.ByteStreams.copy(ByteStreams.java:122)
at org.sonatype.nexus.repository.view.Payload.copy(Payload.java:62)
at org.sonatype.nexus.repository.view.Content.copy(Content.java:113)
at org.sonatype.nexus.repository.httpbridge.internal.DefaultHttpResponseSender.send(DefaultHttpResponseSender.java:94)
at org.sonatype.nexus.repository.httpbridge.internal.ViewServlet.dispatchAndSend(ViewServlet.java:230)
at org.sonatype.nexus.repository.httpbridge.internal.ViewServlet.doService(ViewServlet.java:176)
at org.sonatype.nexus.repository.httpbridge.internal.ViewServlet.service(ViewServlet.java:128)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
at org.eclipse.jetty.ee8.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1146)
at org.eclipse.jetty.ee8.servlet.ServletHolder.handle(ServletHolder.java:640)
at org.eclipse.jetty.ee8.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1374)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:458)
at org.sonatype.nexus.security.SecurityFilter.executeChain(SecurityFilter.java:91)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:373)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:370)
at org.sonatype.nexus.security.SecurityFilter.doFilterInternal(SecurityFilter.java:108)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at com.sonatype.analytics.internal.filter.ThroughputMetricsFilter.doFilter(ThroughputMetricsFilter.java:78)
at javax.servlet.http.HttpFilter.doFilter(HttpFilter.java:127)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at com.sonatype.analytics.internal.filter.ResponseSizeInterceptor.doFilter(ResponseSizeInterceptor.java:57)
at javax.servlet.http.HttpFilter.doFilter(HttpFilter.java:127)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at com.sonatype.analytics.internal.filter.RealtimeThroughputMetricsFilter.doFilter(RealtimeThroughputMetricsFilter.java:69)
at javax.servlet.http.HttpFilter.doFilter(HttpFilter.java:127)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at org.sonatype.nexus.repository.httpbridge.internal.ExhaustRequestFilter.doFilter(ExhaustRequestFilter.java:94)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at com.sonatype.nexus.licensing.internal.LicensingRedirectFilter.doFilter(LicensingRedirectFilter.java:123)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at com.codahale.metrics.servlet.AbstractInstrumentedFilter.doFilter(AbstractInstrumentedFilter.java:112)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at org.sonatype.nexus.internal.web.HeaderPatternFilter.doFilter(HeaderPatternFilter.java:103)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at org.sonatype.nexus.internal.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:84)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at org.sonatype.nexus.internal.web.EnvironmentFilter.doFilter(EnvironmentFilter.java:106)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at org.sonatype.nexus.internal.web.HttpRequestProvider.doFilter(HttpRequestProvider.java:51)
at org.eclipse.jetty.ee8.servlet.FilterHolder.doFilter(FilterHolder.java:171)
at org.eclipse.jetty.ee8.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1348)
at org.eclipse.jetty.ee8.servlet.ServletHandler.doHandle(ServletHandler.java:454)
at org.eclipse.jetty.ee8.nested.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.ee8.security.SecurityHandler.handle(SecurityHandler.java:497)
at org.eclipse.jetty.ee8.nested.HandlerWrapper.handle(HandlerWrapper.java:108)
at org.eclipse.jetty.ee8.nested.ScopedHandler.nextHandle(ScopedHandler.java:183)
at org.eclipse.jetty.ee8.nested.SessionHandler.doHandle(SessionHandler.java:519)
at org.eclipse.jetty.ee8.nested.ScopedHandler.nextHandle(ScopedHandler.java:181)
at org.eclipse.jetty.ee8.nested.ContextHandler.doHandle(ContextHandler.java:885)
at org.eclipse.jetty.ee8.nested.ScopedHandler.nextScope(ScopedHandler.java:152)
at org.eclipse.jetty.ee8.servlet.ServletHandler.doScope(ServletHandler.java:423)
at org.eclipse.jetty.ee8.nested.ScopedHandler.nextScope(ScopedHandler.java:150)
at org.eclipse.jetty.ee8.nested.SessionHandler.doScope(SessionHandler.java:503)
at org.eclipse.jetty.ee8.nested.ScopedHandler.nextScope(ScopedHandler.java:150)
at org.eclipse.jetty.ee8.nested.ContextHandler.doScope(ContextHandler.java:830)
at org.eclipse.jetty.ee8.nested.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.ee8.nested.ContextHandler.handle(ContextHandler.java:1443)
at org.eclipse.jetty.ee8.nested.HttpChannel$RequestDispatchable.dispatch(HttpChannel.java:1291)
at org.eclipse.jetty.ee8.nested.HttpChannel.dispatch(HttpChannel.java:617)
at org.eclipse.jetty.ee8.nested.HttpChannel.handle(HttpChannel.java:459)
at org.eclipse.jetty.ee8.nested.ContextHandler$CoreContextHandler$CoreToNestedHandler.handle(ContextHandler.java:2450)
at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1064)
at org.eclipse.jetty.server.Handler$Wrapper.handle(Handler.java:740)
at io.dropwizard.metrics.jetty12.AbstractInstrumentedHandler.handle(AbstractInstrumentedHandler.java:299)
at org.sonatype.nexus.repository.docker.internal.DockerRequestHandler.handle(DockerRequestHandler.java:43)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:151)
at org.eclipse.jetty.server.Server.handle(Server.java:182)
at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:678)
at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:416)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99)
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:480)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:443)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:311)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:979)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1209)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1164)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.io.IOException: Connection reset by peer
at java.base/sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
at java.base/sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:66)
at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:217)
at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:153)
at java.base/sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:563)
at java.base/java.nio.channels.SocketChannel.write(SocketChannel.java:642)
at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:112)
... 133 common frames omitted
In the original bug report in 2021, we showed that it actually breaks on a bunch of characters, such as the caret ("^") but also the space (" ") which was at that time actually used in the official Fedora repo in the version part of the libjpeg-turbo package name.
The original ticket was closed on May 19th 2023 by Grace Lee as "Resolution: Fixed; Status: Closed" without any further comments. And then the public Jira instance got removed.
But it's still broken. Some recent Fedora package names still look like this: crontabs-1.11^20190603git9e74f2d-5.fc42.noarch.rpm, which makes Nexus return a HTTP/400, same as it did in '21.
Just like OP said, it was indeed mentioned fixed in the 3.55.0 Release Notes (June 5, 2023), but in 3.85.0 the bug is very much alive.
By the way, in 3.75 the bug was still fixed and in 3.80 the bug was back. I didn't try all versions but i did narrow it down to this bracket.