{"record":{"id":"eefef8a45f2f9cc3","repo":"goharbor/harbor","slug":"failed-to-read-chart-yaml-from-the-chart-tgz-file","errorCode":null,"errorMessage":"Failed to read chart.yaml from the chart tgz file. filename {}","messagePattern":"Failed to read chart\\.yaml from the chart tgz file\\. filename (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/migrate_chart/migrate_chart.py","lineNumber":64,"sourceCode":"            return os.path.join(path, member.name)\n\ndef read_chart_version(chart_tgz_path):\n    # Open the chart tgz file\n    with tarfile.open(chart_tgz_path, 'r:gz') as tar:\n        # Find the path to chart.yaml within the tarball\n        chart_yaml_path = find_chart_yaml(tar)\n        if chart_yaml_path:\n            # Extract the chart.yaml file\n            chart_yaml_file = tar.extractfile(chart_yaml_path)\n            if chart_yaml_file is not None:\n                # Load the YAML content from chart.yaml\n                chart_data = yaml.safe_load(chart_yaml_file)\n                # Read the version from chart.yaml\n                version = chart_data.get('version')\n                name = chart_data.get('name')\n                return name, version\n            else:\n                raise Exception(\"Failed to read chart.yaml from the chart tgz file. filename {}\".format(chart_tgz_path))\n        else:\n            raise Exception(\"chart.yaml not found in the chart tgz file. filename {}\".format(chart_tgz_path))\n\nclass ChartV2:\n\n    def __init__(self, filepath:Path):\n        self.filepath = filepath\n        self.project = self.filepath.parts[-2]\n        self.name = \"\"\n        self.version = \"\"\n        try:\n            self.name, self.version = read_chart_version(filepath)\n            if self.name == \"\" or self.version == \"\" or self.name is None or self.version is None :\n                raise Exception('chart name: {} is illegal'.format('-'.join(parts)))\n        except Exception as e:\n            click.echo(\"Skipped chart: {} due to illegal chart name. Error: {}\".format(filepath, e), err=True)\n        return\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/tools/migrate_chart/migrate_chart.py#L46-L82","documentation":"Raised by read_chart_version in Harbor's chart v2->OCI migration tool when find_chart_yaml matched a tar member whose name contains \"Chart.yaml\" but tarfile.extractfile() returned None. extractfile returns None when the matched member is not a regular file (a directory, symlink, fifo, etc.). The exception is caught in ChartV2.__init__, which logs 'Skipped chart ... illegal chart name' and leaves name/version empty so the chart is skipped during the batch migration.","triggerScenarios":"A .tgz under /chart_storage/<project>/ contains an entry matching the substring check (\"Chart.yaml\" in member.name) that is a directory (e.g. a 'Chart.yaml.d' folder), a symlink, or another non-regular file. Because matching is substring-based, unrelated members whose names merely contain 'Chart.yaml' also hit this path.","commonSituations":"Hand-repacked tgz archives, charts packed with non-Helm tooling, archives with symlinked Chart.yaml, or unusual nested directory layouts inside the tarball.","solutions":["Inspect the archive: tar -tzvf <file>.tgz and check the entry type of anything matching Chart.yaml","Repackage the chart with helm package, which guarantees a regular-file Chart.yaml at the chart root","Remove or move the offending tgz out of /chart_storage so the batch run proceeds","Patch find_chart_yaml to only consider regular files whose basename is exactly Chart.yaml"],"exampleFix":"# before\nif \"Chart.yaml\" in member.name:\n    return os.path.join(path, member.name)  # can match dirs/symlinks -> extractfile() returns None\n# after\nif member.isfile() and os.path.basename(member.name) == \"Chart.yaml\":\n    return member.name  # regular file only, extractfile() succeeds","handlingStrategy":"validation","validationCode":"import tarfile\n\ndef has_regular_chart_yaml(tgz_path) -> bool:\n    with tarfile.open(tgz_path, 'r:gz') as tar:\n        return any(m.isfile() and 'Chart.yaml' in m.name for m in tar.getmembers())\n\n# before migration:\n# if not has_regular_chart_yaml(f): quarantine(f)","typeGuard":null,"tryCatchPattern":"try:\n    name, version = read_chart_version(filepath)\nexcept Exception as e:\n    # chart is skipped by design; log and continue the batch\n    click.echo(f'Skipped chart: {filepath} ({e})', err=True)\n    continue","preventionTips":["Always package charts with helm package rather than tar czf","Pre-scan /chart_storage and remove archives without a regular-file Chart.yaml","Never store non-chart tgz files in the migration source directory"],"tags":["python","helm","chart-migration","tarfile","harbor"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}