hashicorp/terraform · error

must be two words separated by an underscore

Error message

must be two words separated by an underscore

What it means

Returned by ParsePlatform (internal/getproviders/types.go:118) when the input string does not split into exactly two parts on underscore. ParsePlatform expects the canonical provider-target form OS_ARCH (e.g. linux_amd64); strings with zero underscores, two or more underscores, or a trailing/leading underscore all fail because strings.Split(str, "_") yields a slice whose length is not 2.

Source

Thrown at internal/getproviders/types.go:118

// The ordering is lexical first by OS and then by Architecture.
// This ordering is primarily just to ensure that results of
// functions in this package will be deterministic. The ordering is not
// intended to have any semantic meaning and is subject to change in future.
func (p Platform) LessThan(other Platform) bool {
	switch {
	case p.OS != other.OS:
		return p.OS < other.OS
	default:
		return p.Arch < other.Arch
	}
}

// ParsePlatform parses a string representation of a platform, like
// "linux_amd64", or returns an error if the string is not valid.
func ParsePlatform(str string) (Platform, error) {
	parts := strings.Split(str, "_")
	if len(parts) != 2 {
		return Platform{}, fmt.Errorf("must be two words separated by an underscore")
	}

	os, arch := parts[0], parts[1]
	if strings.ContainsAny(os, " \t\n\r") {
		return Platform{}, fmt.Errorf("OS portion must not contain whitespace")
	}
	if strings.ContainsAny(arch, " \t\n\r") {
		return Platform{}, fmt.Errorf("architecture portion must not contain whitespace")
	}

	return Platform{
		OS:   os,
		Arch: arch,
	}, nil
}

// CurrentPlatform is the platform where the current program is running.
//

View on GitHub (pinned to c9def3e214)

Solutions

  1. Construct the platform string as OS + "_" + ARCH using the two components rather than assembling by hand.
  2. Prefer using getproviders.CurrentPlatform (runtime.GOOS + runtime.GOARCH) instead of parsing a literal.
  3. Validate the string matches regexp ^[^_\s]+_[^_\s]+$ before calling ParsePlatform.
  4. If parsing user/config input, normalize or reject early with a clear message.

Example fix

// before
platform, err := ParsePlatform("linux")  // len(parts)==1 -> error

// after
platform, err := ParsePlatform("linux_amd64")
// or
platform := getproviders.CurrentPlatform
Defensive patterns

Strategy: validation

Validate before calling

var platformRe = regexp.MustCompile(`^[^_\s]+_[^_\s]+$`)
func safeParsePlatform(s string) (getproviders.Platform, error) {
    if !platformRe.MatchString(s) {
        return getproviders.Platform{}, fmt.Errorf("%q is not OS_ARCH", s)
    }
    return getproviders.ParsePlatform(s)
}

Type guard

func isPlausiblePlatform(s string) bool {
    parts := strings.Split(s, "_")
    return len(parts) == 2 && parts[0] != "" && parts[1] != ""
}

Try / catch

p, err := getproviders.ParsePlatform(str)
if err != nil {
    // fall back to runtime platform or return a clear error
    p = getproviders.CurrentPlatform
}

Prevention

When it happens

Trigger: Calling ParsePlatform with a bare OS ("linux"), an arch-only string ("amd64"), a triple-segment string ("linux_amd64_v1"), or a malformed value derived from user input / lock file / mirror directory name.

Common situations: Hand-constructed platform strings for provider mirror layout, corrupted .terraform.lock.hcl, custom tooling that builds target identifiers from GOOS/GOARCH with a wrong separator, or data sourced from a config field that users typed without the underscore.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/2105af4645157839. Report an issue: GitHub.