theonedev/onedev · error · ClientException

Error reading chart archive: ${e.getMessage()}

Error message

Error reading chart archive: ${e.getMessage()}

What it means

Thrown by HelmPackHandler.handle when an IOException occurs while reading entries of the uploaded .tgz chart archive (opening/reading the tar stream or extracting Chart.yaml). It is a 400 Bad Request telling the client the uploaded archive could not be read, with the underlying IOException message appended.

Source

Thrown at server-plugin/server-plugin-pack-helm/src/main/java/io/onedev/server/plugin/pack/helm/HelmPackHandler.java:204

            Map<String, Object> metadata = null;
            var bytes = baos.toByteArray();

            try (var is = new TarInputStream(new GZIPInputStream(new ByteArrayInputStream(bytes)))) {
                TarEntry entry;
                while ((entry = is.getNextEntry()) != null) {
                    String entryName = entry.getName();
                    if (entryName.equals("Chart.yaml") || entryName.endsWith("/Chart.yaml")) {
                        if (entry.getSize() > MAX_FILE_SIZE)
                            throw new ClientException(SC_BAD_REQUEST, "Chart.yaml is too large");
                        byte[] content = new byte[(int) entry.getSize()];
                        is.read(content);
                        var options = new LoaderOptions();
                        metadata = new Yaml(new SafeConstructor(options)).load(new ByteArrayInputStream(content));
                        break;
                    }
                }                
            } catch (IOException e) {
                throw new ClientException(SC_BAD_REQUEST, "Error reading chart archive: " + e.getMessage());
            }

            if (metadata == null) {
                throw new ClientException(SC_BAD_REQUEST, "Chart.yaml not found in the archive");
            }
            
            var chartName = (String) metadata.get("name");
            var chartVersion = (String) metadata.get("version");
            
            if (chartName == null || chartVersion == null) {
                throw new ClientException(SC_BAD_REQUEST, "Chart name or version not specified");
            }            

            var finalMetadata = metadata;
			var lockName = "update-pack:" + projectId + ":" + HelmPackSupport.TYPE + ":" + chartName + ":" + chartVersion;
            LockUtils.run(lockName, () -> transactionService.run(() -> {
                var project = projectService.load(projectId);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Re-package the chart with 'helm package <chart-dir>' and re-upload the resulting .tgz
  2. Verify the file is a valid gzip tar: 'tar tzf chart.tgz' should list entries including Chart.yaml
  3. Check network/proxy stability and re-upload; ensure the client sends the full request body
  4. Check server logs for the wrapped IOException message to identify the exact read failure

Example fix

// before
curl -T corrupted-chart.tgz https://server/project/~helm
// after
helm package mychart
curl -T mychart-1.0.0.tgz https://server/project/~helm
Defensive patterns

Strategy: validation

Validate before calling

if (!file.getName().endsWith(".tgz")) throw new IllegalArgumentException("not a chart tgz");
try (var in = new FileInputStream(file)) {
    var tar = new TarArchiveInputStream(new GzipCompressorInputStream(in));
    TarArchiveEntry e;
    boolean hasChartYaml = false;
    while ((e = tar.getNextTarEntry()) != null) if (e.getName().equals("Chart.yaml")) { hasChartYaml = true; break; }
    if (!hasChartYaml) throw new IllegalArgumentException("Chart.yaml missing at archive root");
}

Try / catch

try { handler.upload(chartTgz); } catch (ClientException e) { log.error("chart archive rejected: {}", e.getMessage()); }

Prevention

When it happens

Trigger: POST/PUT of a Helm chart package to /~helm where the tar archive is corrupt, truncated, not gzip/tar formatted, or the upload stream fails mid-read so TarArchiveInputStream.getNextEntry/read throws IOException.

Common situations: Uploading a file that is not a real chart tgz (e.g. an HTML error page saved as .tgz), interrupted/partial uploads, proxies corrupting the body, or charts packaged with unusual compression.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/c8d089fe8376e3e7. Report an issue: GitHub.