GoogleContainerTools/skaffold · error

parsing tag %q: %w

Error message

parsing tag %q: %w

What it means

Push validates the tag string with go-containerregistry's name.NewTag (WeakValidation) before pushing, and returns "parsing tag %q" when the string is not a valid image tag. A tag must include a repository path and conform to registry naming rules (lowercase, allowed separators, valid tag suffix).

Source

Thrown at pkg/skaffold/docker/remote.go:105

	return digest(img)
}

// RetrieveRemoteConfig retrieves the remote config file for an image
func RetrieveRemoteConfig(identifier string, cfg Config, platform v1.Platform) (*v1.ConfigFile, error) {
	img, err := getRemoteImage(identifier, cfg, platform)
	if err != nil {
		return nil, err
	}

	return img.ConfigFile()
}

// Push pushes the tarball image
func Push(tarPath, tag string, cfg Config, platforms []specs.Platform) (string, error) {
	t, err := name.NewTag(tag, name.WeakValidation)
	if err != nil {
		return "", fmt.Errorf("parsing tag %q: %w", tag, err)
	}

	i, err := tarball.ImageFromPath(tarPath, nil)
	if err != nil {
		return "", fmt.Errorf("reading image %q: %w", tarPath, err)
	}

	if err := remote.Write(t, i, remote.WithAuthFromKeychain(primaryKeychain)); err != nil {
		return "", fmt.Errorf("%s %q: %w", sErrors.PushImageErr, t, err)
	}

	return getRemoteDigest(tag, cfg, platforms)
}

func getRemoteImage(identifier string, cfg Config, platform v1.Platform) (v1.Image, error) {
	ref, err := parseReference(identifier, cfg)
	if err != nil {
		return nil, err

View on GitHub (pinned to a1189de023)

Solutions

  1. Inspect the logged tag value — it is printed with %q, making empty strings and stray whitespace visible.
  2. Normalize the image name to lowercase and strip any scheme (docker://, https://).
  3. Ensure the string is a tag, not a digest reference (use @sha256:... only where references are accepted).
  4. Trim trailing slashes/colons; a tag like "repo/img:" or "repo/img:v1@digest" is invalid for NewTag.
  5. Test the exact string with `name.NewTag(tag, name.WeakValidation)` in a snippet or with `crane tag` to validate.

Example fix

// before
image := "https://gcr.io/Project/App:V1"
docker.Push(tarPath, image, cfg, nil)
// after
image := strings.ToLower(strings.TrimPrefix("https://gcr.io/Project/App:V1", "https://"))
docker.Push(tarPath, image, cfg, nil)
Defensive patterns

Strategy: validation

Validate before calling

var tagRe = regexp.MustCompile(`^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[0-9]+)?/)?[a-z0-9]+(?:[._-][a-z0-9]+)*(?:/[a-z0-9]+(?:[._-][a-z0-9]+)*)*:[\w][\w.-]{0,127}$`)
func validateTag(tag string) error {
	if !tagRe.MatchString(tag) {
		return fmt.Errorf("invalid image tag: %q", tag)
	}
	_, err := name.NewTag(tag, name.WeakValidation)
	return err
}

Type guard

func isValidTag(s string) bool {
	_, err := name.NewTag(s, name.WeakValidation)
	return err == nil
}

Try / catch

if err := validateTag(tag); err != nil { return err }
if _, err := docker.Push(tarPath, tag, cfg, platforms); err != nil {
	if strings.Contains(err.Error(), "parsing tag") {
		return fmt.Errorf("check image name: must be lowercase, no scheme, valid tag: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: Push called with a tag missing the repository part (e.g. "myimage" without registry/namespace is still fine, but empty or containing uppercase, spaces, invalid characters like :tag:extra, or just ":latest").

Common situations: Empty tag because an upstream templating variable didn't render; uppercase image names (e.g. "MyApp") which registries reject; full image URLs with scheme prefix ("https://...") or digest references passed where a tag is required.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/08f63b58cea99fdb. Report an issue: GitHub.