VariableBlock rejects optional object attribute defaults
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 68/100
Research direction
Start in variable_test.go with the provided variableSuite reproduction, then trace VariableBlock.parseVariableType and the paths that process CLI files, environment variables, prompts, and variable defaults. Compare the current typeexpr.Type call with TypeConstraintWithDefaults and verify that nested defaults are applied before conversion. Done means the focused test passes and partial objects receive the documented nested defaults without changing existing conversion or validation behavior.
Written by the indexing model from the issue text.
Description
Summary
VariableBlock cannot use optional object attributes with defaults in a variable type, even though HCL supports this syntax for type constraints:
variable "provider" {
type = object({
type = optional(string, "openai")
endpoint = string
retry = optional(object({
attempts = optional(number, 3)
}), {})
})
default = {
endpoint = "https://example.test/v1"
}
}
Planning fails while parsing the variable type. This prevents callers from passing a partial object and relying on field-level defaults, which is particularly useful for provider-style configuration.
Reproduction test
The following test can be added directly to variable_test.go in the existing variableSuite:
func (s *variableSuite) TestExecuteBeforePlan_ObjectOptionalAttributeDefaults() {
s.dummyFsWithFiles(map[string]string{
"test.hcl": `variable "provider" {
type = object({
type = optional(string, "openai")
endpoint = string
retry = optional(object({
attempts = optional(number, 3)
}), {})
})
default = {
endpoint = "https://example.test/v1"
}
}`,
})
config, err := BuildDummyConfig("/", "", nil, nil)
require.NoError(s.T(), err)
variable := Blocks[*VariableBlock](config)[0]
s.Equal(cty.ObjectVal(map[string]cty.Value{
"type": cty.StringVal("openai"),
"endpoint": cty.StringVal("https://example.test/v1"),
"retry": cty.ObjectVal(map[string]cty.Value{
"attempts": cty.NumberIntVal(3),
}),
}), *variable.variableValue)
}
Run:
go test ./... -run 'TestVariableSuite/TestExecuteBeforePlan_ObjectOptionalAttributeDefaults' -count=1
Actual result:
--- FAIL: TestVariableSuite/TestExecuteBeforePlan_ObjectOptionalAttributeDefaults
Received unexpected error:
test.hcl:3,16-24: Invalid type specification;
Optional attribute modifier is only for type constraints, not for exact types.,
and 2 other diagnostic(s)
Configurations containing optional(type, default) can also report:
Optional attribute modifier expects only one argument: the attribute type.
Expected behavior
BuildDummyConfig should succeed. The evaluated var.provider value should be:
{
type = "openai"
endpoint = "https://example.test/v1"
retry = {
attempts = 3
}
}
A top-level variable default is not an equivalent workaround: once a caller supplies a partial object, it does not merge defaults into omitted nested attributes.
Root cause
On current main, VariableBlock.parseVariableType uses:
t, diag := typeexpr.Type(typeAttr.Expr)
typeexpr.Type parses an exact type. HCL exposes typeexpr.TypeConstraintWithDefaults specifically for variable-style type constraints with optional(type, default).
TypeConstraintWithDefaults returns both the target cty.Type and a *typeexpr.Defaults tree. The defaults must be retained by VariableBlock and applied to the selected input value before conversion. Merely changing the parser without calling Defaults.Apply would accept the syntax but still lose the intended defaults.
Suggested direction
- Parse variable types with
typeexpr.TypeConstraintWithDefaults. - Store the returned defaults on
VariableBlock. - Apply them to values from CLI files, environment variables, prompts, and the variable-level
defaultbeforeconvert.Convert. - Preserve the current type conversion and validation behavior.
- Add coverage for nested optional object defaults and partial caller-supplied objects.
Observed against Azure/golden main at 6e9a3fc2760e6f8440e4dfe8d0b1360886588bdd.
- Dominant language
- Go
- Stars
- 3
- Forks
- 13
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Azure/golden
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 3/5 1-2 days Newbie friendliness 72/100
-
Difficulty 4/5 3-5 days Newbie friendliness 55/100
-
Difficulty 3/5 1-2 days Newbie friendliness 52/100
Similar issues
-
bug docs
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
bug needs-acceptance wg/evaluation-quality
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
vllm-project/semantic-router#4424 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
NVIDIA/k8s-device-plugin#2076 ·
Maintainers usually reply within 1 day
-
Documentation help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
golang/go#81933 · 2 comments ·
Maintainers usually reply within 1 day