opentofu/opentofu · error

invalid reference: artifact tag or digest not allowed

Error message

invalid reference: artifact tag or digest not allowed

What it means

OpenTofu addresses providers in OCI registries as registry domain plus repository path, with no tag or digest — version selection is the job of version constraints. When parsing an address that contains a '/', orasregistry.ParseReference succeeds but yields a non-empty Reference (tag or digest component), this error rejects it. Registries serve exactly one artifact per repository+version mapping, so a tag would make the mirror target ambiguous.

Source

Thrown at internal/command/cliconfig/ociauthconfig/repository_addr.go:48

	// implement something similar inline here or find an alternative external library
	// to use for this.
	// We're actually using the _reference_ parser here, since a reference incorporates
	// a repository address, but we'll reject after the fact any result that includes
	// a tag or digest portion since we're not intending to accept addresses of specific
	// artifacts.

	if strings.Count(addr, "/") != 0 {
		// This seems to be an address with both a registry and a repository path.
		ref, parseErr := orasregistry.ParseReference(addr)
		if parseErr != nil {
			// The ORAS function returns errors with sufficient context that any
			// further decoration we might add here would be redundant. For example,
			// this might return an error whose message is
			// "invalid reference: invalid registry invalid:thing:blah".
			return "", "", parseErr
		}
		if ref.Reference != "" {
			return "", "", fmt.Errorf("invalid reference: artifact tag or digest not allowed")
		}
		return ref.Registry, ref.Repository, nil
	}

	// If we get here then it seems like we have _just_ a domain part. ORAS does
	// not have a separate function just for parsing a domain, so we'll borrow the
	// validate function from its reference parser instead.
	ref := &orasregistry.Reference{
		Registry: addr,
	}
	err = ref.ValidateRegistry()
	// ValidateRegistry returns an error with a string like "invalid reference: invalid registry invalid:thing:blah"
	return addr, "", err
}

View on GitHub (pinned to 3561785c48)

Solutions

  1. Remove the :tag or @sha256:... suffix from the address — keep only domain/namespace/type
  2. Pin versions where they belong: the provider's version constraint in the Terraform/OpenTofu configuration or the mirror's metadata
  3. Double-check the repository path still has the right number of segments after removing the suffix

Example fix

# before
oci_mirror {
  include "registry.example.com/mirror/terraform:1.9.0" {}
}
# after
oci_mirror {
  include "registry.example.com/mirror/terraform" {}
}
# pin in code instead:
required_providers { tofu = { source = "registry.example.com/mirror/terraform", version = "1.9.0" } }
Defensive patterns

Strategy: validation

Validate before calling

func hasTagOrDigest(addr string) bool {
    // strip scheme if present, then look for ':' after the first '/' or '@'
    if i := strings.Index(addr, "/"); i >= 0 {
        rest := addr[i:]
        return strings.Contains(rest, ":") || strings.Contains(addr, "@")
    }
    return strings.Contains(addr, ":") || strings.Contains(addr, "@")
}

Prevention

When it happens

Trigger: An oci_mirror 'include' pattern or installation address like registry.example.com/mirror/hashicorp/terraform:1.9.0 or .../terraform@sha256:abcd — the ':tag' or '@digest' suffix makes ref.Reference non-empty and triggers the error.

Common situations: Users familiar with docker pull syntax assuming tags are allowed; copying image references from registry UIs; attempting to pin a provider by digest in the mirror configuration.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/8e79bf1d85cdae16. Report an issue: GitHub.