{"record":{"id":"3aebf8bfe6eaaef7","repo":"hashicorp/terraform","slug":"cannot-decode-tfvars-from-a-null-value","errorCode":null,"errorMessage":"cannot decode tfvars from a null value","messagePattern":"cannot decode tfvars from a null value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/builtin/providers/terraform/functions.go","lineNumber":99,"sourceCode":"\tresult := f.Bytes()\n\treturn cty.StringVal(string(result)), nil\n}\n\nfunc decodeTfvarsFunc(args []cty.Value) (cty.Value, error) {\n\t// These error checks should not be hit in practice because the language\n\t// runtime should check them before calling, so this is just for robustness\n\t// and completeness.\n\tif len(args) > 1 {\n\t\treturn cty.NilVal, function.NewArgErrorf(1, \"too many arguments; only one expected\")\n\t}\n\tif len(args) == 0 {\n\t\treturn cty.NilVal, fmt.Errorf(\"exactly one argument is required\")\n\t}\n\tif args[0].Type() != cty.String {\n\t\treturn cty.NilVal, fmt.Errorf(\"argument must be a string\")\n\t}\n\tif args[0].IsNull() {\n\t\treturn cty.NilVal, fmt.Errorf(\"cannot decode tfvars from a null value\")\n\t}\n\tif !args[0].IsKnown() {\n\t\t// If our input isn't known then we can't even predict the result\n\t\t// type, since it will be an object type decided based on which\n\t\t// arguments and values we find in the string.\n\t\treturn cty.DynamicVal, nil\n\t}\n\n\t// If we get here then we know that:\n\t// - there's exactly one element in args\n\t// - it's a string\n\t// - it is known and non-null\n\t// So therefore the following is guaranteed to succeed.\n\tsrc := []byte(args[0].AsString())\n\n\t// As usual when we wrap HCL stuff up in functions, we end up needing to\n\t// stuff HCL diagnostics into plain string error messages. This produces\n\t// a non-ideal result but is still better than hiding the HCL-provided","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/builtin/providers/terraform/functions.go#L81-L117","documentation":"decode_tfvars refuses to parse a null input because there is no tfvars content to decode. The function's declared parameter type is non-nullable cty.String, so reaching this branch means the language runtime failed to enforce the schema. It is a defensive guard, not a normal user-facing path.","triggerScenarios":"Calling decode_tfvars(null) or decode_tfvars(var.x) where var.x resolves to null and the runtime did not short-circuit; invoking decodeTfvarsFunc directly from Go with cty.NullVal(cty.String) as args[0].","commonSituations":"A Terraform Core / plugin dispatch bug that ignores the function's parameter schema; direct unit tests calling the Go function with a null cty.Value instead of routing through the runtime.","solutions":["Ensure the caller honors the function schema (Parameter Type=cty.String, no AllowNull) so null never reaches the function","Coalesce the input before calling: decode_tfvars(coalesce(var.maybe_null, \"\"))","If invoking from Go, guard args[0].IsNull() (and args[0].IsKnown()) before calling decodeTfvarsFunc"],"exampleFix":"// before\ndecode_tfvars(var.maybe_null)\n// after\ndecode_tfvars(coalesce(var.maybe_null, \"\"))","handlingStrategy":"validation","validationCode":"// In Go, before invoking decodeTfvarsFunc directly:\nif len(args) != 1 || args[0].IsNull() || !args[0].IsKnown() || args[0].Type() != cty.String {\n    return cty.NilVal, fmt.Errorf(\"decode_tfvars requires one known, non-null string\")\n}\n// In HCL, ensure a non-null input before the call:\n// decode_tfvars(coalesce(var.maybe_null, \"\"))","typeGuard":"// HCL-level guard: guarantee a non-null string reaches decode_tfvars\nlocals {\n  safe_src = var.maybe_null == null ? \"\" : var.maybe_null\n}\n// then: decode_tfvars(local.safe_src)","tryCatchPattern":null,"preventionTips":["Treat decode_tfvars as taking a non-nullable string and coalesce upstream","When calling the Go func directly, replicate the runtime's schema checks (type, null, known-ness, arity)","Write a unit test that passes cty.NullVal(cty.String) to confirm your guard fires before the provider error"],"tags":["terraform","go","cty","hcl","decode-tfvars","null-guard"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}