amir20/dozzle · error

invalid image reference

Error message

invalid image reference %q: empty tag

What it means

ParseReference splits the last ':' in the repository path as a tag separator (registry ports are stripped earlier). If the colon exists but nothing follows it, the tag is empty and this error is returned.

Solutions

  1. Remove the trailing ':' to use the implicit default tag (latest)
  2. Supply an explicit tag, e.g. nginx:1.25
  3. Fix the interpolation so the tag variable is set before building the reference

Example fix

// before
ref := fmt.Sprintf("nginx:%s", os.Getenv("TAG")) // TAG unset -> "nginx:"
// after
tag := os.Getenv("TAG")
if tag == "" { tag = "latest" }
ref := fmt.Sprintf("nginx:%s", tag)
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasSuffix(ref, ":") {
    return fmt.Errorf("reference %q has an empty tag", ref)
}

Type guard

func hasTag(ref string) bool {
    i := strings.LastIndex(ref, ":")
    return i != -1 && i < len(ref)-1 && !strings.Contains(ref[i+1:], "/")
}

Try / catch

if _, err := imagecheck.ParseReference(ref); err != nil {
    if strings.Contains(err.Error(), "empty tag") {
        ref = strings.TrimSuffix(ref, ":") // fall back to latest
    }
}

Prevention

When it happens

Trigger: Passing references ending in ':' such as "nginx:", "repo:5000/app:", or "localhost:5000/foo:".

Common situations: String templates that interpolate an empty tag variable ("app:" + version where version is ""), CLI/env config with a dangling colon, copy-paste errors where the tag was deleted.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/b80eed1ed53e1d7b. Report an issue: GitHub.

Appendix: source

Thrown at internal/imagecheck/reference.go:131

			remainder = remainder[i+1:]
		}
	}

	// Docker Hub answers to several names. They have to collapse to one, or a
	// reference written as index.docker.io/library/nginx never lines up with
	// the "nginx@sha256:..." that Docker records locally.
	if _, aliased := dockerHubAliases[registry]; aliased {
		registry = defaultRegistry
	}

	tag := ""
	// Only treat a colon as a tag separator when it is not part of a registry
	// port, which has already been stripped above.
	if i := strings.LastIndex(remainder, ":"); i != -1 {
		tag = remainder[i+1:]
		remainder = remainder[:i]
		if tag == "" {
			return Reference{}, fmt.Errorf("invalid image reference %q: empty tag", ref)
		}
	}

	if remainder == "" {
		return Reference{}, fmt.Errorf("invalid image reference %q: empty repository", ref)
	}

	// Official images live under library/ but are referenced without it.
	if registry == defaultRegistry && !strings.Contains(remainder, "/") {
		remainder = "library/" + remainder
	}

	if tag == "" && digest == "" {
		tag = defaultTag
	}

	return Reference{
		Registry:   registry,

View on GitHub (pinned to d9463cbe21)