hashicorp/packer · error
unhandled buildvar type: %T
Error message
unhandled buildvar type: %T
What it means
ConvertPluginConfigValueToHCLValue converts a plugin-provided build variable (a plain Go interface{}) into a cty.Value for HCL2 interpolation. Packer throws this error when the value's Go type is not one of the supported kinds (bool, string, uint8, float64, int64, uint64, []string, []uint8, []int64, []uint64), so it cannot be represented as an HCL value.
Source
Thrown at hcl2template/utils.go:186
vals[i] = cty.NumberIntVal(ev)
}
if len(vals) == 0 {
buildValue = cty.ListValEmpty(cty.Number)
} else {
buildValue = cty.ListVal(vals)
}
case []uint64:
vals := make([]cty.Value, len(v))
for i, ev := range v {
vals[i] = cty.NumberUIntVal(ev)
}
if len(vals) == 0 {
buildValue = cty.ListValEmpty(cty.Number)
} else {
buildValue = cty.ListVal(vals)
}
default:
return cty.Value{}, fmt.Errorf("unhandled buildvar type: %T", v)
}
return buildValue, nil
}
// GetVarsByType walks through a hcl body, and gathers all the Traversals that
// have a root type matching one of the specified top-level labels.
//
// This will only work on finite, expanded, HCL bodies.
func GetVarsByType(block *hcl.Block, topLevelLabels ...string) []hcl.Traversal {
var travs []hcl.Traversal
switch body := block.Body.(type) {
case *hclsyntax.Body:
travs = getVarsByTypeForHCLSyntaxBody(body)
default:
attrs, _ := body.JustAttributes()
for _, attr := range attrs {
travs = append(travs, attr.Expr.Variables()...)View on GitHub (pinned to eb36e3c3e4)
Solutions
- Coerce the build variable to a supported type before passing it: convert Go int to int64, maps/structs to string (e.g. JSON-encode), and []interface{} to []string
- Fix the plugin/builder code that produces the variable so it emits one of the supported types
- If it's your code calling ConvertPluginConfigValueToHCLValue, pre-validate types with a type switch and convert unsupported ones yourself
- Check the Packer/SDK version: newer SDKs may type values differently; align the producer and consumer versions
Example fix
// before buildVars["port"] = 8080 // Go int -> unhandled // after buildVars["port"] = int64(8080) // or strconv.Itoa: buildVars["port"] = "8080"
Defensive patterns
Strategy: type-guard
Validate before calling
func isSupportedBuildVarType(v interface{}) bool {
switch v.(type) {
case bool, string, uint8, float64, int64, uint64, []string, []uint8, []int64, []uint64:
return true
}
return false
} Type guard
func coerceBuildVar(v interface{}) interface{} {
switch t := v.(type) {
case int:
return int64(t)
case int32:
return int64(t)
case uint:
return uint64(t)
case map[string]interface{}:
b, _ := json.Marshal(t)
return string(b)
default:
return v
}
} Prevention
- Only populate buildVars with the documented supported types; normalize ints to int64 and maps to strings
- When writing plugins, follow the SDK conventions for generated variable types
- Add a unit test that round-trips every build variable through ConvertPluginConfigValueToHCLValue
- Check plugin/SDK version compatibility when upgrading
When it happens
Trigger: HCL2Prepare (on HCL2Provisioner or HCL2PostProcessor) iterates buildVars and calls this converter; a build variable of an unhandled type — e.g. int (plain, not int64), map[string]string, []interface{}, nil, or a struct — hits the default branch.
Common situations: A builder or plugin passes build variables with types outside the whitelist (e.g. Go int or a map) via the build's generated variables; a caller constructs buildVars map[string]interface{} manually with an int or nested value instead of the supported primitives/slices.
Related errors
- unsupported dependency type %q; locals can only depend on lo
- no release version found for constraints: %q
- source must be specified when auto_generate is not enabled
- Only one of script or scripts can be specified.
- Must supply an 'elevated_user' if 'elevated_password' provid
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/b34a13d41815db5c.
Report an issue: GitHub.