{"record":{"id":"cbb4b1d21b96d616","repo":"hashicorp/nomad","slug":"key-q-has-invalid-type-t","errorCode":null,"errorMessage":"key %q has invalid type %T","messagePattern":"key %q has invalid type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/taskenv/util.go","lineNumber":123,"sourceCode":"\tdst := make(map[string]cty.Value, len(src))\n\n\tfor k, vI := range src {\n\t\tswitch v := vI.(type) {\n\t\tcase string:\n\t\t\tdst[k] = cty.StringVal(v)\n\n\t\tcase cty.Value:\n\t\t\tdst[k] = v\n\n\t\tcase map[string]any:\n\t\t\to, err := ctyify(v)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdst[k] = cty.ObjectVal(o)\n\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"key %q has invalid type %T\", k, v)\n\t\t}\n\t}\n\n\treturn dst, nil\n}\n","sourceCodeStart":105,"sourceCodeEnd":129,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/taskenv/util.go#L105-L129","documentation":"ctyify converts the nested map[string]any variable tree into cty values, supporting only string, cty.Value, and map[string]any. Any other Go type (int, bool, []string, nil, etc.) triggers this error naming the key and its actual %T type. AllValues calls it on the whole tree and treats failure as a programming error, since user input should already be normalized to strings.","triggerScenarios":"A value in EnvMap, NodeAttrs, or TaskSecrets is not a string when AllValues -> ctyify walks it, e.g. an int/bool inserted directly into those maps, or code placing a non-string into a nested map that feeds AllValues.","commonSituations":"Plugins or hooks populating NodeAttrs with native Go types instead of strings; tests seeding EnvMap with non-string values; third-party code mutating TaskEnv maps directly.","solutions":["Convert the offending value to a string before adding it (fmt.Sprintf(\"%v\", v) or strconv) so ctyify sees a string","Only populate TaskEnv maps via the documented builder APIs, which enforce string values","Check the key name and %T in the message to locate the code inserting the wrong type","If it originates in Nomad core, file an upstream bug — invalid user input is expected to be cleaned earlier"],"exampleFix":"// before\nbuilder.NodeAttrs[\"custom.count\"] = 42\n// after\nbuilder.NodeAttrs[\"custom.count\"] = \"42\"","handlingStrategy":"validation","validationCode":"// Go: sanitize variable maps before building the TaskEnv\nfunc stringOnly(m map[string]any) error {\n    for k, v := range m {\n        switch v.(type) {\n        case string, map[string]any, cty.Value:\n        default:\n            return fmt.Errorf(\"key %q must be string-valued, got %T\", k, v)\n        }\n    }\n    return nil\n}","typeGuard":"// Go\nfunc isCtyifiable(v any) bool {\n    switch v.(type) {\n    case string, cty.Value, map[string]any:\n        return true\n    }\n    return false\n}","tryCatchPattern":"// Go\nvars, perKeyErrs, err := tenv.AllValues()\nif err != nil && strings.Contains(err.Error(), \"has invalid type\") {\n    return nil, fmt.Errorf(\"non-string variable inserted into TaskEnv: %w\", err)\n}","preventionTips":["Store all env/node attribute values as strings at the boundary","Use the documented env builder APIs instead of mutating TaskEnv maps directly","Run stringOnly-style validation in tests for plugin-provided attributes","Check the %T in the message to find the code passing native Go types"],"tags":["nomad","taskenv","cty","type-error"],"backgroundTag":"unsupported-variable-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"}