hashicorp/terraform · error

invalid provider matching pattern

Error message

invalid provider matching pattern %q: must have either two or three slash-separated segments

What it means

Thrown by ParseMultiSourceMatchingPatterns when a provider matching pattern string splits on '/' into fewer than 2 or more than 3 segments. A pattern must be either 'namespace/type' (2 segments) or 'host/namespace/type' (3 segments); the leading host segment is optional and defaults to the default registry host. Anything else (a bare name, a single segment, four-plus segments, or a leading/trailing slash producing empty parts) is rejected before any hostname/namespace/type normalization runs.

Solutions

  1. Rewrite the pattern to exactly two segments (namespace/type, e.g. hashicorp/aws) or three segments (host/namespace/type, e.g. registry.terraform.io/hashicorp/aws).
  2. Remove any leading or trailing slash and any empty middle segment that strings.Split would turn into an extra part.
  3. If you intended a host wildcard, keep three segments and use '*/*/*' (host wildcards force namespace and type wildcards too).
  4. Validate the whole include/exclude slice with ParseMultiSourceMatchingPatterns in a config-load test before deploying.

Example fix

// before
include = ["aws"]
exclude = ["registry.terraform.io/hashicorp/aws/zip"]

// after
include = ["hashicorp/aws"]
exclude = ["registry.terraform.io/hashicorp/aws"]
Defensive patterns

Strategy: validation

Validate before calling

// Validate a provider matching pattern before calling ParseMultiSourceMatchingPatterns.
func validPatternSegmentCount(s string) error {
    parts := strings.Split(s, "/")
    if len(parts) < 2 || len(parts) > 3 {
        return fmt.Errorf("pattern %q must have 2 or 3 slash-separated segments", s)
    }
    for _, p := range parts {
        if p == "" {
            return fmt.Errorf("pattern %q has an empty segment", s)
        }
    }
    return nil
}

// usage:
// for _, p := range includePatterns {
//     if err := validPatternSegmentCount(p); err != nil { return err }
// }

Prevention

When it happens

Trigger: Calling ParseMultiSourceMatchingPatterns (or wiring CLI/config provider_installation include/exclude arrays) with values such as "aws", "hashicorp/aws/extra", "a/b/c/d", "/aws", or "hashicorp/". The check at multi_source.go:150 is len(parts) < 2 || len(parts) > 3 right after strings.Split(str, "/").

Common situations: Typos in a .terraformrc / terraform.rc provider_installation block's include/exclude list; copying a full source address like registry.terraform.io/hashicorp/aws and adding an extra path; forgetting the namespace and writing only the type; a stray leading or trailing slash from templating.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/0b905f369fb84212. Report an issue: GitHub.

Appendix: source

Thrown at internal/getproviders/multi_source.go:151

// The Provider address values in a MultiSourceMatchingPatterns are special in
// that any of Hostname, Namespace, or Type can be getproviders.Wildcard
// to indicate that any concrete value is permitted for that segment.
type MultiSourceMatchingPatterns []addrs.Provider

// ParseMultiSourceMatchingPatterns parses a slice of strings containing the
// string form of provider matching patterns and, if all the given strings are
// valid, returns the corresponding, normalized, MultiSourceMatchingPatterns
// value.
func ParseMultiSourceMatchingPatterns(strs []string) (MultiSourceMatchingPatterns, error) {
	if len(strs) == 0 {
		return nil, nil
	}

	ret := make(MultiSourceMatchingPatterns, len(strs))
	for i, str := range strs {
		parts := strings.Split(str, "/")
		if len(parts) < 2 || len(parts) > 3 {
			return nil, fmt.Errorf("invalid provider matching pattern %q: must have either two or three slash-separated segments", str)
		}
		host := defaultRegistryHost
		explicitHost := len(parts) == 3
		if explicitHost {
			givenHost := parts[0]
			if givenHost == "*" {
				host = svchost.Hostname(Wildcard)
			} else {
				normalHost, err := svchost.ForComparison(givenHost)
				if err != nil {
					return nil, fmt.Errorf("invalid hostname in provider matching pattern %q: %s", str, err)
				}

				// The remaining code below deals only with the namespace/type portions.
				host = normalHost
			}

			parts = parts[1:]

View on GitHub (pinned to d32a084675)