hashicorp/packer · error

must have at least one character

Error message

must have at least one character

What it means

ParsePluginPart normalizes individual parts of plugin source addresses (hostname label, namespace, name). An empty string cannot be a valid part, so it is rejected immediately. This underlies plugin source parsing and normalization checks.

Source

Thrown at hcl2template/addrs/plugin.go:64

// an error if the string contains invalid characters.
//
// A plugin part is processed in the same way as an individual label in a DNS
// domain name: it is transformed to lowercase per the usual DNS case mapping
// and normalization rules and may contain only letters, digits, and dashes.
// Additionally, dashes may not appear at the start or end of the string.
//
// These restrictions are intended to allow these names to appear in fussy
// contexts such as directory/file names on case-insensitive filesystems,
// repository names on GitHub, etc. We're using the DNS rules in particular,
// rather than some similar rules defined locally, because the hostname part
// of an addrs.Plugin is already a hostname and it's ideal to use exactly
// the same case folding and normalization rules for all of the parts.
//
// It's valid to pass the result of this function as the argument to a
// subsequent call, in which case the result will be identical.
func ParsePluginPart(given string) (string, error) {
	if len(given) == 0 {
		return "", fmt.Errorf("must have at least one character")
	}

	// We're going to process the given name using the same "IDNA" library we
	// use for the hostname portion, since it already implements the case
	// folding rules we want.
	//
	// The idna library doesn't expose individual label parsing directly, but
	// once we've verified it doesn't contain any dots we can just treat it
	// like a top-level domain for this library's purposes.
	if strings.ContainsRune(given, '.') {
		return "", fmt.Errorf("dots are not allowed")
	}

	// We don't allow names containing multiple consecutive dashes, just as
	// a matter of preference: they look confusing, or incorrect.
	// This also, as a side-effect, prevents the use of the "punycode"
	// indicator prefix "xn--" that would cause the IDNA library to interpret
	// the given name as punycode, because that would be weird and unexpected.

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Provide a complete plugin source with all parts, e.g. github.com/hashicorp/amazon
  2. Check required_plugins entries in your HCL2 template for empty/missing segments
  3. Ensure variables/locals interpolated into plugin addresses are non-empty

Example fix

// before
source = "github.com/hashicorp/" // empty name part
// after
source = "github.com/hashicorp/amazon"
Defensive patterns

Strategy: validation

Validate before calling

// before using a plugin address
parts := strings.Split(addr, "/")
for _, p := range parts { if p == "" { return errors.New("empty plugin address part: " + addr) } }

Type guard

func validPart(s string) bool { return len(s) > 0 && !strings.ContainsRune(s, '.') }

Prevention

When it happens

Trigger: Calling ParsePluginPart(""), or indirectly via ParsePluginSourceString / IsPluginPartNormalized when a plugin source string like `plugins.packer.io/namespace/name` is missing one of its components.

Common situations: An HCL2 required_plugins block with an empty or malformed source string; programmatic address construction passing an empty segment; plugin source missing namespace or name.

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/b0dbad318ca574ee. Report an issue: GitHub.