hashicorp/nomad · error
expected map/object cty value, got %T
Error message
expected map/object cty value, got %T
What it means
After recursive conversion succeeds, CtyValueToMapInterface asserts the result is map[string]any. Although the type check on the cty side should guarantee this, the conversion layer can still yield a different Go type; this %T-based error is the defensive fallback.
Source
Thrown at helper/pluginutils/hclutils/util.go:92
}
if val.IsNull() {
return nil, nil
}
t := val.Type()
if !t.IsMapType() && !t.IsObjectType() {
return nil, fmt.Errorf("expected map/object cty value, got %s", t.FriendlyName())
}
v, err := ctyValueToInterface(val)
if err != nil {
return nil, err
}
m, ok := v.(map[string]any)
if !ok {
return nil, fmt.Errorf("expected map/object cty value, got %T", v)
}
return m, nil
}
func ctyValueToInterface(val cty.Value) (interface{}, error) {
t := val.Type()
if val.IsNull() {
return nil, nil
}
if !val.IsKnown() {
return nil, fmt.Errorf("value is not known")
}
switch {
case t.IsPrimitiveType():View on GitHub (pinned to 482b49bf1a)
Solutions
- Inspect the printed Go type (%T) and fix the converter or input so it produces map[string]any.
- Ensure the input value really is a cty map/object before calling (the earlier check filters most cases).
- If you own the code, extend ctyValueToInterface to map the offending type correctly.
Example fix
// before
v, _ := ctyValueToInterface(val)
m := v.(map[string]any)
// after
m, ok := v.(map[string]any)
if !ok {
return fmt.Errorf("unexpected converted type %T", v)
} Defensive patterns
Strategy: type-guard
Validate before calling
v, err := ctyValueToInterface(val)
if err != nil {
return err
}
if _, ok := v.(map[string]any); !ok {
return fmt.Errorf("converter produced %T, expected map[string]any", v)
} Type guard
m, ok := v.(map[string]any)
if !ok {
return fmt.Errorf("expected map[string]any, got %T", v)
} Try / catch
m, err := CtyValueToMapInterface(val)
if err != nil {
return fmt.Errorf("plugin config conversion failed: %w", err)
} Prevention
- Keep the recursive converter's return types aligned with map[string]any
- Add unit tests covering every cty type branch
- Re-run conversion tests after changing cty version
When it happens
Trigger: ctyValueToInterface returns a non-map Go value (defensive path; normally unreachable when the input passed the map/object type check, e.g. due to future changes in the converter).
Common situations: Rare — mostly hit after code changes to the recursive converter or when capsule/custom types produce unusual Go values; surfaced in tests like TestCtyValueToMapInterface_InvalidType.
Related errors
- value is not known
- expected map/object cty value, got %s
- cannot serialize %s
- internal plugin %s doesn't meet base plugin interface
- invalid digest format
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/c5beae3db1e74c02.
Report an issue: GitHub.