Skip to content

Docker image tag duplicated during skill publish leading skill publish to always fail #178

@jfiore-pg

Description

@jfiore-pg

Bug: Docker image tag duplicated during skill publish leading skill publish to always fail

Description

When publishing a skill using arctl skill publish, the Docker image tag is appended twice, resulting in an invalid image reference.

Steps to Reproduce

  1. Run the skill publish command:
arctl skill publish gl-analyze-build-result --docker-url "docker.io/user" --dry-run
  1. Observe the output shows duplicated tags:
[DRY RUN] Would build Docker image: docker.io/user/gl-analyze-build-result:latest:latest
  1. Without --dry-run, the build fails:
ERROR: failed to build: invalid tag "docker.io/user/gl-analyze-build-result:latest:latest": invalid reference format

Expected Behavior

The Docker image tag should be appended only once:

docker.io/user/gl-analyze-build-result:latest

Actual Behavior

The version is appended twice:

docker.io/user/gl-analyze-build-result:latest:latest

This occurs consistently on every skill publish command, regardless of the --tag flag value.

Root Cause Analysis

The bug is in internal/cli/skill/publish.go at lines 169-181.

Current (Broken) Flow:

ver := dockerTag          // Line 169: ver = "latest" (default)
if ver == "" {
    ver = "latest"
}

// Line 176: BuildLocalImageName already appends :version
// Result: "gl-analyze-build-result:latest"
repoName := common.BuildLocalImageName(fm.Name, ver)

// Line 181: BuildRegistryImageName calls BuildLocalImageName AGAIN
// This appends :version a second time
imageRef := common.BuildRegistryImageName(strings.TrimSuffix(dockerUrl, "/"), repoName, ver)

The Problem:

In internal/cli/common/common.go line 27:

func BuildRegistryImageName(registryURL, name, version string) string {
    return fmt.Sprintf("%s/%s", strings.TrimSuffix(registryURL, "/"), BuildLocalImageName(name, version))
}

The function design expects name to be just the project name (e.g., "gl-analyze-build-result"), but it's being called with an already-versioned name from BuildLocalImageName (e.g., "gl-analyze-build-result:latest"). This causes the version to be appended twice.

Solution

Remove the intermediate call to BuildLocalImageName on line 176 of publish.go. Pass the unversioned project name directly to BuildRegistryImageName:

// BEFORE (lines 176, 181):
repoName := common.BuildLocalImageName(fm.Name, ver)
// ...
imageRef := common.BuildRegistryImageName(strings.TrimSuffix(dockerUrl, "/"), repoName, ver)

// AFTER:
imageRef := common.BuildRegistryImageName(strings.TrimSuffix(dockerUrl, "/"), fm.Name, ver)

This allows BuildRegistryImageName to correctly call BuildLocalImageName once, appending the version exactly once.

Version

Introduced in: v0.1.24 (commit 0351c9c, PR #165)

Affects: v0.1.24, v0.1.25

Bug introduced: February 13, 2026

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions