goharbor/harbor · warning

Artifact already exist in harbor

Error message

Artifact already exist in harbor

What it means

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.

Source

Thrown at tools/migrate_chart/migrate_chart.py:94

            self.name, self.version = read_chart_version(filepath)
            if self.name == "" or self.version == "" or self.name is None or self.version is None :
                raise Exception('chart name: {} is illegal'.format('-'.join(parts)))
        except Exception as e:
            click.echo("Skipped chart: {} due to illegal chart name. Error: {}".format(filepath, e), err=True)
        return

    def __check_exist(self, hostname, username, password):
        return requests.get(CHART_URL_PATTERN.format(
                host=hostname,
                project=self.project,
                name=self.name,
                version=self.version),
                auth=requests.auth.HTTPBasicAuth(username, password))

    def migrate(self, hostname, username, password):
        res = self.__check_exist(hostname, username, password)
        if res.status_code == 200:
            raise Exception("Artifact already exist in harbor")
        if res.status_code == 401:
            raise Exception(res.reason)

        oci_ref = "oci://{host}/{project}".format(
            host=hostname,
            project=self.project)

        return subprocess.run([MIGRATE_CHART_SCRIPT, HELM_CMD, self.filepath, oci_ref],
        text=True, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)


@click.command()
@click.option('--hostname', default='127.0.0.1', help='the password to login harbor')
@click.option('--username', default='admin', help='The username to login harbor')
@click.option('--password', default='Harbor12345', help='the password to login harbor')
def migrate(hostname, username, password):
    """
    Migrate chart v2 to harbor oci registry

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Treat it as expected on re-runs — the artifact is already migrated; filter these out of errs when reviewing results
  2. Delete the existing artifact first (DELETE /api/v2.0/projects/{project}/repositories/{name}/artifacts/{version}) and re-run
  3. Bump the chart version in Chart.yaml and repackage if a fresh copy is actually needed
  4. Patch migrate() to log-and-skip on status 200 instead of raising

Example fix

# before
if res.status_code == 200:
    raise Exception("Artifact already exist in harbor")
# after
if res.status_code == 200:
    click.echo("Already migrated: {}/{}:{}".format(self.project, self.name, self.version), err=True)
    return subprocess.CompletedProcess(args=[], returncode=0)
Defensive patterns

Strategy: try-catch

Try / catch

try:
    result = chart.migrate(hostname, username, password)
except Exception as e:
    if 'already exist' in str(e):
        # idempotent re-run: already migrated, not an actual failure
        continue
    errs.append(str(e))

Prevention

When it happens

Trigger: 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.

Common situations: Idempotent re-runs after interruption, retrying a failed batch, dev/staging chart sources sharing one Harbor instance.

Related errors


AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16). Data as JSON: /api/errors/94ec6df21247ec78. Report an issue: GitHub.