Nexus cannot generate URL in helm index when version contains a '+' or url contains a ' '

We have a proxy helm repo where some of the versions contain a ‘+’. The URL in the index.yaml from the upstream has a space instead of the +. I’m not sure if Nexus builds the URL from the version, or if it does something to the URL from upstream, but the result is that there’s an error in the log for each chart with a ‘+’ and the URL is missing in the index.yaml in Nexus.

Upstrem provides this (note the ’ ’ in “102.0.1 up”):

  rancher-monitoring-crd:
    - apiVersion: v1
      created: 2023-12-20T10:53:14.665202946Z
      description: Installs the CRDs for rancher-monitoring.
      digest: 4c4dcc1df2b4bc1762f8b5e498bc87a54cab73dd0c94481f9ed80b5f9239efe5
      name: rancher-monitoring-crd
      urls:
        - rancher-monitoring-crd/rancher-monitoring-crd-102.0.1 up40.1.2.tgz
      type: application
      annotations:
        catalog.cattle.io/certified: rancher
        catalog.cattle.io/hidden: "true"
        catalog.cattle.io/namespace: cattle-monitoring-system
        catalog.cattle.io/release-name: rancher-monitoring-crd
      version: "102.0.1+up40.1.2"

This results in an error in nexus logs like:

2024-05-30 19:31:13,297+0000 ERROR [streamcopier-14-thread-4]  *TASK com.sonatype.repository.helm.internal.metadata.IndexYamlAbsoluteUrlRewriter - Invalid URI in index.yaml
java.net.URISyntaxException: Illegal character in path at index 53: rancher-monitoring-crd/rancher-monitoring-crd-102.0.1 up40.1.2.tgz
	at java.net.URI$Parser.fail(URI.java:2847)
	at java.net.URI$Parser.checkChars(URI.java:3020)
	at java.net.URI$Parser.parseHierarchical(URI.java:3104)
	at java.net.URI$Parser.parse(URI.java:3062)
	at java.net.URI.<init>(URI.java:588)
	at org.apache.http.client.utils.URIBuilder.<init>(URIBuilder.java:82)
	at com.sonatype.repository.helm.internal.metadata.IndexYamlAbsoluteUrlRewriterSupport.rewriteUrl(IndexYamlAbsoluteUrlRewriterSupport.java:77)
	at com.sonatype.repository.helm.internal.metadata.IndexYamlAbsoluteUrlRewriterSupport.lambda$2(IndexYamlAbsoluteUrlRewriterSupport.java:68)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
	at com.sonatype.repository.helm.internal.metadata.IndexYamlAbsoluteUrlRewriterSupport.rewriteUrls(IndexYamlAbsoluteUrlRewriterSupport.java:71)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
	at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)
	at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:272)
	at java.util.Iterator.forEachRemaining(Iterator.java:116)
	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
	at com.sonatype.repository.helm.internal.metadata.IndexYamlAbsoluteUrlRewriterSupport.updateUrls(IndexYamlAbsoluteUrlRewriterSupport.java:58)
	at com.sonatype.repository.helm.internal.metadata.IndexYamlAbsoluteUrlRewriter.lambda$2(IndexYamlAbsoluteUrlRewriter.java:67)
	at java.util.function.Consumer.lambda$andThen$0(Consumer.java:65)
	at org.sonatype.nexus.thread.io.StreamCopier.lambda$2(StreamCopier.java:148)
	at org.sonatype.nexus.thread.internal.MDCAwareRunnable.run(MDCAwareRunnable.java:40)
	at org.apache.shiro.subject.support.SubjectRunnable.doRun(SubjectRunnable.java:120)
	at org.apache.shiro.subject.support.SubjectRunnable.run(SubjectRunnable.java:108)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)

And the result in Nexus’ index.yaml:

rancher-monitoring-crd:
  - apiVersion: v1
    name: rancher-monitoring-crd
    description: Installs the CRDs for rancher-monitoring.
    version: 102.0.1+up40.1.2
    created: 2023-12-20T10:53:14.665Z
    digest: 4c4dcc1df2b4bc1762f8b5e498bc87a54cab73dd0c94481f9ed80b5f9239efe5
    urls: []

Hi @brousch this looks like a bug if you wouldn’t mind filing it in the public issues: Issues · sonatype/nexus-public · GitHub

I have submitted Nexus cannot handle space in helm chart URL · Issue #401 · sonatype/nexus-public · GitHub