{"record":{"id":"c5beae3db1e74c02","repo":"hashicorp/nomad","slug":"expected-map-object-cty-value-got-t","errorCode":null,"errorMessage":"expected map/object cty value, got %T","messagePattern":"expected map/object cty value, got %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/pluginutils/hclutils/util.go","lineNumber":92,"sourceCode":"\t}\n\n\tif val.IsNull() {\n\t\treturn nil, nil\n\t}\n\n\tt := val.Type()\n\tif !t.IsMapType() && !t.IsObjectType() {\n\t\treturn nil, fmt.Errorf(\"expected map/object cty value, got %s\", t.FriendlyName())\n\t}\n\n\tv, err := ctyValueToInterface(val)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm, ok := v.(map[string]any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"expected map/object cty value, got %T\", v)\n\t}\n\n\treturn m, nil\n}\n\nfunc ctyValueToInterface(val cty.Value) (interface{}, error) {\n\tt := val.Type()\n\n\tif val.IsNull() {\n\t\treturn nil, nil\n\t}\n\n\tif !val.IsKnown() {\n\t\treturn nil, fmt.Errorf(\"value is not known\")\n\t}\n\n\tswitch {\n\tcase t.IsPrimitiveType():","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/pluginutils/hclutils/util.go#L74-L110","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nv, _ := ctyValueToInterface(val)\nm := v.(map[string]any)\n// after\nm, ok := v.(map[string]any)\nif !ok {\n    return fmt.Errorf(\"unexpected converted type %T\", v)\n}","handlingStrategy":"type-guard","validationCode":"v, err := ctyValueToInterface(val)\nif err != nil {\n    return err\n}\nif _, ok := v.(map[string]any); !ok {\n    return fmt.Errorf(\"converter produced %T, expected map[string]any\", v)\n}","typeGuard":"m, ok := v.(map[string]any)\nif !ok {\n    return fmt.Errorf(\"expected map[string]any, got %T\", v)\n}","tryCatchPattern":"m, err := CtyValueToMapInterface(val)\nif err != nil {\n    return fmt.Errorf(\"plugin config conversion failed: %w\", err)\n}","preventionTips":["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"],"tags":["cty","type-assertion","go"],"backgroundTag":"unexpected-type","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}