{"record":{"id":"b0dbad318ca574ee","repo":"hashicorp/packer","slug":"must-have-at-least-one-character","errorCode":null,"errorMessage":"must have at least one character","messagePattern":"must have at least one character","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hcl2template/addrs/plugin.go","lineNumber":64,"sourceCode":"// an error if the string contains invalid characters.\n//\n// A plugin part is processed in the same way as an individual label in a DNS\n// domain name: it is transformed to lowercase per the usual DNS case mapping\n// and normalization rules and may contain only letters, digits, and dashes.\n// Additionally, dashes may not appear at the start or end of the string.\n//\n// These restrictions are intended to allow these names to appear in fussy\n// contexts such as directory/file names on case-insensitive filesystems,\n// repository names on GitHub, etc. We're using the DNS rules in particular,\n// rather than some similar rules defined locally, because the hostname part\n// of an addrs.Plugin is already a hostname and it's ideal to use exactly\n// the same case folding and normalization rules for all of the parts.\n//\n// It's valid to pass the result of this function as the argument to a\n// subsequent call, in which case the result will be identical.\nfunc ParsePluginPart(given string) (string, error) {\n\tif len(given) == 0 {\n\t\treturn \"\", fmt.Errorf(\"must have at least one character\")\n\t}\n\n\t// We're going to process the given name using the same \"IDNA\" library we\n\t// use for the hostname portion, since it already implements the case\n\t// folding rules we want.\n\t//\n\t// The idna library doesn't expose individual label parsing directly, but\n\t// once we've verified it doesn't contain any dots we can just treat it\n\t// like a top-level domain for this library's purposes.\n\tif strings.ContainsRune(given, '.') {\n\t\treturn \"\", fmt.Errorf(\"dots are not allowed\")\n\t}\n\n\t// We don't allow names containing multiple consecutive dashes, just as\n\t// a matter of preference: they look confusing, or incorrect.\n\t// This also, as a side-effect, prevents the use of the \"punycode\"\n\t// indicator prefix \"xn--\" that would cause the IDNA library to interpret\n\t// the given name as punycode, because that would be weird and unexpected.","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/hcl2template/addrs/plugin.go#L46-L82","documentation":"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.","triggerScenarios":"Calling ParsePluginPart(\"\"), or indirectly via ParsePluginSourceString / IsPluginPartNormalized when a plugin source string like `plugins.packer.io/namespace/name` is missing one of its components.","commonSituations":"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.","solutions":["Provide a complete plugin source with all parts, e.g. github.com/hashicorp/amazon","Check required_plugins entries in your HCL2 template for empty/missing segments","Ensure variables/locals interpolated into plugin addresses are non-empty"],"exampleFix":"// before\nsource = \"github.com/hashicorp/\" // empty name part\n// after\nsource = \"github.com/hashicorp/amazon\"","handlingStrategy":"validation","validationCode":"// before using a plugin address\nparts := strings.Split(addr, \"/\")\nfor _, p := range parts { if p == \"\" { return errors.New(\"empty plugin address part: \" + addr) } }","typeGuard":"func validPart(s string) bool { return len(s) > 0 && !strings.ContainsRune(s, '.') }","tryCatchPattern":null,"preventionTips":["Always write full three-part plugin sources (host/namespace/name)","Check required_plugins blocks for truncated addresses","Avoid interpolating potentially empty values into plugin addresses"],"tags":["hcl2","plugin-address","validation"],"backgroundTag":"empty-identifier","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}