{"record":{"id":"94ec6df21247ec78","repo":"goharbor/harbor","slug":"artifact-already-exist-in-harbor","errorCode":null,"errorMessage":"Artifact already exist in harbor","messagePattern":"Artifact already exist in harbor","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"tools/migrate_chart/migrate_chart.py","lineNumber":94,"sourceCode":"            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\n    def __check_exist(self, hostname, username, password):\n        return requests.get(CHART_URL_PATTERN.format(\n                host=hostname,\n                project=self.project,\n                name=self.name,\n                version=self.version),\n                auth=requests.auth.HTTPBasicAuth(username, password))\n\n    def migrate(self, hostname, username, password):\n        res = self.__check_exist(hostname, username, password)\n        if res.status_code == 200:\n            raise Exception(\"Artifact already exist in harbor\")\n        if res.status_code == 401:\n            raise Exception(res.reason)\n\n        oci_ref = \"oci://{host}/{project}\".format(\n            host=hostname,\n            project=self.project)\n\n        return subprocess.run([MIGRATE_CHART_SCRIPT, HELM_CMD, self.filepath, oci_ref],\n        text=True, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)\n\n\n@click.command()\n@click.option('--hostname', default='127.0.0.1', help='the password to login harbor')\n@click.option('--username', default='admin', help='The username to login harbor')\n@click.option('--password', default='Harbor12345', help='the password to login harbor')\ndef migrate(hostname, username, password):\n    \"\"\"\n    Migrate chart v2 to harbor oci registry","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/tools/migrate_chart/migrate_chart.py#L76-L112","documentation":"Raised by ChartV2.migrate when the Harbor v2.0 existence check GET /api/v2.0/projects/{project}/repositories/{name}/artifacts/{version} returns 200 — the chart already exists at the destination and the tool refuses to overwrite it. The exception propagates to the CLI loop, gets appended to the errs list, and the batch continues with the next chart.","triggerScenarios":"Re-running the migration tool after a previous complete or partial run; a chart whose name+version was already pushed to Harbor by CI, a manual helm push, or an earlier migration attempt.","commonSituations":"Idempotent re-runs after interruption, retrying a failed batch, dev/staging chart sources sharing one Harbor instance.","solutions":["Treat it as expected on re-runs — the artifact is already migrated; filter these out of errs when reviewing results","Delete the existing artifact first (DELETE /api/v2.0/projects/{project}/repositories/{name}/artifacts/{version}) and re-run","Bump the chart version in Chart.yaml and repackage if a fresh copy is actually needed","Patch migrate() to log-and-skip on status 200 instead of raising"],"exampleFix":"# before\nif res.status_code == 200:\n    raise Exception(\"Artifact already exist in harbor\")\n# after\nif res.status_code == 200:\n    click.echo(\"Already migrated: {}/{}:{}\".format(self.project, self.name, self.version), err=True)\n    return subprocess.CompletedProcess(args=[], returncode=0)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    result = chart.migrate(hostname, username, password)\nexcept Exception as e:\n    if 'already exist' in str(e):\n        # idempotent re-run: already migrated, not an actual failure\n        continue\n    errs.append(str(e))","preventionTips":["Track migrated charts externally so re-runs skip them at the source","Review migration_errors.txt knowing 'already exist' entries are informational","Delete artifacts you genuinely want re-pushed before re-running the tool"],"tags":["python","harbor","chart-migration","idempotency"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}