diff --git a/jobspec2/parse_test.go b/jobspec2/parse_test.go index 4facf6458..94d37df7b 100644 --- a/jobspec2/parse_test.go +++ b/jobspec2/parse_test.go @@ -196,6 +196,28 @@ job "example" { require.Equal(t, meta, out.Meta) } +// TestParse_UnsetVariables asserts that variables that have neither types nor +// values return early instead of panicking. +func TestParse_UnsetVariables(t *testing.T) { + hcl := ` +variable "region_var" {} +job "example" { + datacenters = [for s in ["dc1", "dc2"] : upper(s)] + region = var.region_var +} +` + + _, err := ParseWithConfig(&ParseConfig{ + Path: "input.hcl", + Body: []byte(hcl), + ArgVars: []string{}, + AllowFS: true, + }) + + require.Error(t, err) + require.Contains(t, err.Error(), "Unset variable") +} + func TestParse_Locals(t *testing.T) { hcl := ` variables { diff --git a/jobspec2/types.config.go b/jobspec2/types.config.go index 56ab1a090..0c25d9f2f 100644 --- a/jobspec2/types.config.go +++ b/jobspec2/types.config.go @@ -71,6 +71,13 @@ func (c *jobConfig) decodeBody(body hcl.Body) hcl.Diagnostics { diags = append(diags, moreDiags...) diags = append(diags, c.evaluateLocalVariables(c.LocalBlocks)...) + // Errors at this point are likely syntax errors which can result in + // invalid state when we try to decode the rest of the job. If we continue + // we may panic and that will obscure the error, so return early so the + // user can be told how to fix their jobspec. + if diags.HasErrors() { + return diags + } nctx := c.EvalContext() diags = append(diags, c.decodeJob(content, nctx)...)