Skip to content

bake: panic when using undefined typed variables as null #3463

@rrjjvv

Description

@rrjjvv

Contributing guidelines

I've found a bug and checked that ...

  • ... the documentation does not mention anything about my problem
  • ... there are no open or closed issues that are related to my problem

Description

Using a typed variable which has no default value and no provided value will panic in at least two scenarios when being used as build args. My original scenario was using it in a ternary operation, e.g. FOO = FOO == null ? "bar" : FOO. While coming up with a minimal reproduction, I found that a simple FOO = FOO will panic as well, though with a slightly different call stack. This only applies to typed variables.

Given that this is specific to typed variables, I'm assuming the issue is directly related to my previous contributions in this area and will look into it (feel free to assign to me). Thus, I'm going to skimp on areas of this report as they are likely irrelevant. (If it ends up being something totally different, I'll add more details at that point.)

Expected behaviour

A panic should not occur. Even if there's some technicality behind why my examples are actually invalid, it should result in a user-facing error message.

Actual behaviour

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x7fcba1]

Buildx version

github.com/docker/buildx v0.29.1 a32761a

Docker info


Builders list

NAME/NODE           DRIVER/ENDPOINT                   STATUS     BUILDKIT   PLATFORMS
buildkit-dev        docker-container                                        
 \_ buildkit-dev0    \_ unix:///var/run/docker.sock   inactive              
foo                 docker-container                                        
 \_ foo0             \_ unix:///var/run/docker.sock   running    v0.24.0    linux/amd64 (+4), linux/arm64, linux/arm (+2), linux/ppc64le, (7 more)
jd                  docker-container                                        
 \_ jd0              \_ unix:///var/run/docker.sock   running    v0.22.0    linux/amd64 (+4), linux/arm64, linux/arm (+2), linux/ppc64le, (7 more)
temp                docker-container                                        
 \_ temp0            \_ unix:///var/run/docker.sock   inactive              
default*            docker                                                  
 \_ default          \_ default                       running    v0.25.1    linux/amd64 (+4), linux/arm64, linux/arm (+2), linux/ppc64le, (6 more)
teamx               docker                                                  
 \_ teamx            \_ teamx                         running    v0.25.1    linux/amd64 (+4), linux/arm64, linux/arm (+2), linux/ppc64le, (6 more)
worker              docker                                                  
 \_ worker           \_ worker                        running    v0.24.0    linux/amd64 (+2), linux/arm64, linux/arm (+2), linux/ppc64le, (5 more)

Configuration

Minimal example of my original issue:

variable "FOO" {
  type = string
}

target "default" {
  args = {
    ARG = FOO == null ? "yo" : FOO
  }
}

Note that ARG = FOO == null actually works... it results in "ARG": "true", so it's being evaluated as null, which suggests the false expression is the one causing the panic:

$ docker buildx bake --print
[+] Building 0.0s (1/1) FINISHED                                                                                                                                                                                                                   
 => [internal] load local bake definitions                                                                                                                                                                                                    0.0s
 => => reading docker-bake.hcl 107B / 107B                                                                                                                                                                                                    0.0s
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x7fcba1]

goroutine 1 [running]:
github.com/zclconf/go-cty/cty.Type.FriendlyName(...)
	github.com/zclconf/go-cty@v1.17.0/cty/type.go:47
github.com/hashicorp/hcl/v2/hclsyntax.describeConditionalTypeMismatch({{0x2f03390?, 0xc0000108e5?}}, {{0x0?, 0x0?}})
	github.com/hashicorp/hcl/v2@v2.24.0/hclsyntax/expression.go:1069 +0x401
github.com/hashicorp/hcl/v2/hclsyntax.(*ConditionalExpr).Value(0xc0003aa540, 0xc00000e9a8)
	github.com/hashicorp/hcl/v2@v2.24.0/hclsyntax/expression.go:767 +0x68a
github.com/hashicorp/hcl/v2/hclsyntax.(*ObjectConsExpr).Value(0xc0006946e0, 0xc00000e9a8)
	github.com/hashicorp/hcl/v2@v2.24.0/hclsyntax/expression.go:1211 +0x27d
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.DecodeExpression({0x2c506c0?, 0x2c51858?}, {0x74931a5151d8, 0xc0006946e0}, 0x2f34b00?, {0xc00053ae00, 0xc00036c088})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:288 +0x9b
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.decodeBodyToStruct({0x2c506c0?, 0x2c51858?}, {0x2f03278, 0xc0006872e0}, 0xc00000e9a8, {0x2936ec0?, 0xc00036c000?, 0x4166df?})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:138 +0xd67
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.decodeBodyToValue({0x2c506c0?, 0x2c51858?}, {0x2f03278, 0xc0006872e0}, 0xc00000e9a8, {0x2936ec0?, 0xc00036c000?, 0x50d76d?})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:57 +0xee
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.DecodeBody({0x2c506c0?, 0x0?}, {0x2f03278, 0xc0006872e0}, 0xc00000e9a8, {0x272d3a0?, 0xc00036c000?})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:30 +0x11b
github.com/docker/buildx/bake/hclparser.decodeBody(...)
	github.com/docker/buildx/bake/hclparser/hclparser.go:1239
github.com/docker/buildx/bake/hclparser.(*parser).resolveBlock(0xc000075400, 0xc00036b6c0, 0x0)
	github.com/docker/buildx/bake/hclparser/hclparser.go:525 +0xebd
github.com/docker/buildx/bake/hclparser.Parse({0x2f03240, 0xc00000e6f0}, {0x2c50158?, 0xc000434540?, 0x2c506b8?}, {0x276fa20, 0xc000434570})
	github.com/docker/buildx/bake/hclparser/hclparser.go:929 +0x1f1a
github.com/docker/buildx/bake.ParseFiles({0xc000434510, 0x1, 0x1?}, 0xc000434540)
	github.com/docker/buildx/bake/bake.go:380 +0xa4f
github.com/docker/buildx/bake.ReadTargets({0xc00022af20?, 0x0?}, {0xc000434510?, 0xc0004075f0?, 0x0?}, {0xc0003a2800, 0x1, 0x0?}, {0x0, 0x0, ...}, ...)
	github.com/docker/buildx/bake/bake.go:199 +0x46
github.com/docker/buildx/commands.runBake({_, _}, {_, _}, {_, _, _}, {{0x454d780, 0x0, 0x0}, ...}, ...)
	github.com/docker/buildx/commands/bake.go:231 +0x1f3e
github.com/docker/buildx/commands.bakeCmd.func1(0xc000035208, {0xc0003a2430, 0x0, 0x1})
	github.com/docker/buildx/commands/bake.go:493 +0x372
github.com/docker/cli/cli-plugins/plugin.RunPlugin.func1.1.2(0xc000035208, {0xc0003a2430, 0x0, 0x1})
	github.com/docker/cli@v28.4.0+incompatible/cli-plugins/plugin/plugin.go:65 +0x64
github.com/spf13/cobra.(*Command).execute(0xc000035208, {0xc000406f20, 0x1, 0x1})
	github.com/spf13/cobra@v1.10.1/command.go:1015 +0xaaa
github.com/spf13/cobra.(*Command).ExecuteC(0xc0004ad508)
	github.com/spf13/cobra@v1.10.1/command.go:1148 +0x46f
github.com/spf13/cobra.(*Command).Execute(...)
	github.com/spf13/cobra@v1.10.1/command.go:1071
github.com/docker/cli/cli-plugins/plugin.RunPlugin(0xc0002e8140, 0xc000034c08, {{0x298177a, 0x5}, {0x298be5f, 0xb}, {0x2ec9ad0, 0x7}, {0x0, 0x0}, ...})
	github.com/docker/cli@v28.4.0+incompatible/cli-plugins/plugin/plugin.go:80 +0x145
main.runPlugin(0xc0002e8140)
	github.com/docker/buildx/cmd/buildx/main.go:64 +0xca
main.run(0xc0002e8140)
	github.com/docker/buildx/cmd/buildx/main.go:78 +0xe5
main.main()
	github.com/docker/buildx/cmd/buildx/main.go:88 +0x8c

Similarly, this panics as well... null is a legitimate value, and it's reasonable to expect that an undefined variable is equivalent to null in this usage:

variable "FOO" {
  type = string
}

target "default" {
  args = {
    ARG = FOO
  }
}
$ docker buildx bake --print
[+] Building 0.0s (1/1) FINISHED                                                                                                                                                                                                                   
 => [internal] load local bake definitions                                                                                                                                                                                                    0.0s
 => => reading docker-bake.hcl 86B / 86B                                                                                                                                                                                                      0.0s
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x7a4d1e]

goroutine 1 [running]:
github.com/zclconf/go-cty/cty.Type.FriendlyName(...)
	github.com/zclconf/go-cty@v1.17.0/cty/type.go:47
github.com/zclconf/go-cty/cty/convert.MismatchMessage({{0x0?, 0x0?}}, {{0x2f03390?, 0xc0000108e5?}})
	github.com/zclconf/go-cty@v1.17.0/cty/convert/mismatch_msg.go:57 +0x2de
github.com/zclconf/go-cty/cty/convert.mismatchMessageCollectionsFromStructural({{0x2f031d0?, 0xc000069ae0?}}, {{0x2f03198?, 0xc000069b00?}})
	github.com/zclconf/go-cty@v1.17.0/cty/convert/mismatch_msg.go:191 +0x38d
github.com/zclconf/go-cty/cty/convert.MismatchMessage({{0x2f031d0?, 0xc000069ae0?}}, {{0x2f03198?, 0xc000069b00?}})
	github.com/zclconf/go-cty@v1.17.0/cty/convert/mismatch_msg.go:51 +0x45a
github.com/zclconf/go-cty/cty/convert.Convert({{{0x2f031d0?, 0xc000069ae0?}}, {0x259e020?, 0xc00033d680?}}, {{0x2f03198?, 0xc000069b00?}})
	github.com/zclconf/go-cty@v1.17.0/cty/convert/public.go:49 +0x168
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.DecodeExpression({0x2c506c0?, 0x2c51858?}, {0x751c18f50178, 0xc000204640}, 0x2f34b00?, {0xc000310b40, 0xc0003ce088})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:295 +0x114
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.decodeBodyToStruct({0x2c506c0?, 0x2c51858?}, {0x2f03278, 0xc0000c7ec0}, 0xc000780318, {0x2936ec0?, 0xc0003ce000?, 0x4166df?})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:138 +0xd67
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.decodeBodyToValue({0x2c506c0?, 0x2c51858?}, {0x2f03278, 0xc0000c7ec0}, 0xc000780318, {0x2936ec0?, 0xc0003ce000?, 0x50d76d?})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:57 +0xee
github.com/docker/buildx/bake/hclparser/gohcl.DecodeOptions.DecodeBody({0x2c506c0?, 0x0?}, {0x2f03278, 0xc0000c7ec0}, 0xc000780318, {0x272d3a0?, 0xc0003ce000?})
	github.com/docker/buildx/bake/hclparser/gohcl/decode.go:30 +0x11b
github.com/docker/buildx/bake/hclparser.decodeBody(...)
	github.com/docker/buildx/bake/hclparser/hclparser.go:1239
github.com/docker/buildx/bake/hclparser.(*parser).resolveBlock(0xc000074280, 0xc000357930, 0x0)
	github.com/docker/buildx/bake/hclparser/hclparser.go:525 +0xebd
github.com/docker/buildx/bake/hclparser.Parse({0x2f03240, 0xc000780138}, {0x2c50158?, 0xc000261050?, 0x2c506b8?}, {0x276fa20, 0xc000261080})
	github.com/docker/buildx/bake/hclparser/hclparser.go:929 +0x1f1a
github.com/docker/buildx/bake.ParseFiles({0xc000260ff0, 0x1, 0x1?}, 0xc000261050)
	github.com/docker/buildx/bake/bake.go:380 +0xa4f
github.com/docker/buildx/bake.ReadTargets({0xc0001aaf20?, 0x0?}, {0xc000260ff0?, 0xc000376cc0?, 0x0?}, {0xc000502570, 0x1, 0x0?}, {0x0, 0x0, ...}, ...)
	github.com/docker/buildx/bake/bake.go:199 +0x46
github.com/docker/buildx/commands.runBake({_, _}, {_, _}, {_, _, _}, {{0x454d780, 0x0, 0x0}, ...}, ...)
	github.com/docker/buildx/commands/bake.go:231 +0x1f3e
github.com/docker/buildx/commands.bakeCmd.func1(0xc0004fd208, {0xc0001fe110, 0x0, 0x1})
	github.com/docker/buildx/commands/bake.go:493 +0x372
github.com/docker/cli/cli-plugins/plugin.RunPlugin.func1.1.2(0xc0004fd208, {0xc0001fe110, 0x0, 0x1})
	github.com/docker/cli@v28.4.0+incompatible/cli-plugins/plugin/plugin.go:65 +0x64
github.com/spf13/cobra.(*Command).execute(0xc0004fd208, {0xc000376020, 0x1, 0x1})
	github.com/spf13/cobra@v1.10.1/command.go:1015 +0xaaa
github.com/spf13/cobra.(*Command).ExecuteC(0xc0004f5508)
	github.com/spf13/cobra@v1.10.1/command.go:1148 +0x46f
github.com/spf13/cobra.(*Command).Execute(...)
	github.com/spf13/cobra@v1.10.1/command.go:1071
github.com/docker/cli/cli-plugins/plugin.RunPlugin(0xc00042a3c0, 0xc0004fcc08, {{0x298177a, 0x5}, {0x298be5f, 0xb}, {0x2ec9ad0, 0x7}, {0x0, 0x0}, ...})
	github.com/docker/cli@v28.4.0+incompatible/cli-plugins/plugin/plugin.go:80 +0x145
main.runPlugin(0xc00042a3c0)
	github.com/docker/buildx/cmd/buildx/main.go:64 +0xca
main.run(0xc00042a3c0)
	github.com/docker/buildx/cmd/buildx/main.go:78 +0xe5
main.main()
	github.com/docker/buildx/cmd/buildx/main.go:88 +0x8c

Build logs


Additional info

There are at least two potential workarounds:

  1. remove the typing (if it's only used as documentation and not actually relied on)
  2. add an explicit default; default = null avoids the panic in each of those scenarios

I'm assuming the fix will be effectively implementing the second behind the scenes.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions