helm: default function treats boolean false as not defined, and applies default

values.yaml:

someKey: false

in template:

{{ default true .Values.someKey }}

I would expect this to return false, as someKey is defined, and its value is false, however it returns true.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 45
  • Comments: 42 (5 by maintainers)

Commits related to this issue

Most upvoted comments

You have the arguments flipped in the wrong direction. It should be {{ default .Values.somekey false }}. default takes its first argument as the value to check if it exists, then defaults to the second argument if it’s not defined.

Hey guys, you can try to use this one solution, which we are using:

someKey: false
anotherKey: {{ hasKey .Values "someKey" | ternary .Values.someKey true }}

@bacongobbler If this is working as intended (that you cannot use default with booleans). Can it be added to documentation, as a warning? Or reopen the issue if it isn’t working as intended.

Hi @bacongobbler ,

What if I’d like to use this in a block if in my template? Something like:

{{- if (default $foo true) }}
someSetting: "bar"
{{- end }}

and I want the someSetting to not render only when $foo is explicitly set to false.

@gabordk and anyone else that my encounter this issue, this is my workaround that I am using is a few templates:

{{- if or (.Values.enabled) (eq (.Values.enabled | toString) "<nil>") }}
someSetting: bar
{{- end }}

in action:

$> cat chart/values.yaml

enabled: true

$> helm template chart/

---
someSetting: bar
otherSetting: foo
$> cat chart/values.yaml

$> helm template chart/

---
someSetting: bar
otherSetting: foo
$> cat chart/values.yaml

enabled: false

$> helm template chart/

---
otherSetting: foo

I use this:

{{- if or .Values.myVar (not (hasKey .Values "myVar")) }}
...
{{- end }}

This basically says “render the block if the value is true, OR if the value is false because the key does not exist”.

I find this easier to understand than the ternary function and does not depend on the variable’s value.

I can’t believe this hasn’t been reopened

{{- if ne "false" (.value | toString) }}
# Do something 
{{- end }}

Hi @bacongobbler ,

What if I’d like to use this in a block if in my template? Something like:

{{- if (default $foo true) }}
someSetting: "bar"
{{- end }}

and I want the someSetting to not render only when $foo is explicitly set to false.

simplest workaround I’ve come up is this

list nil true | has .Values.vaultEnabled

Thanks @schollii, worked for me. The documentation should definitely state that values that evaluate to false cannot be used with the default function, or the function should be changed to work similarly to Jinja2’s default filter:

image

I am surprised that I still see this bug in 2021…

The “if + default” make me confused since it behaviors differently with different default value.

with

{{- if .Values.somekey| default false }}
<code block>
{{-end }}

and explicitly define “somekey: true” , then <code-block> will be executed as expected.

But on the other hand,

{{- if .Values.somekey| default true}}
<code block>
{{-end }}

and explicitly define “somekey: false” , then <code-block> is still be executed which is not expected at all.

I personally picked up the workaround provided by @sshishov in https://github.com/helm/helm/issues/3308#issuecomment-701367019, but I still wonder why helm works with if/default in such a confusing behavior as mentioned above.

{{ if (eq (default "true" (.Values.myVar|toString|lower)) "true") }}
...
{{- end }}

Currently using this. Convert all to lower case string and make a direct comparison. If not specified use "true"

This is the workaround I use:

{{ if or (not (hasKey . "enabled")) (eq (coalesce .enabled false) true) }}
...
{{ end }}

Obviously, if the dictionary you’re checking is something like $foo:

{{ if or (not (hasKey $foo "enabled")) (eq (coalesce $foo.enabled false) true) }}
...
{{ end }}

The reason I’m using coalesce is because eq .enabled true fails (error calling eq: invalid type for comparison) with null errors for some dastardly reason.

Obviously, the only works if enabled is either a boolean, or absent. If it’s actually null, then the above won’t work.

five years later and i fall into the same hole now, this issue should be fixed

{{if ((.Values.health).enabled)}}

This works well for me, in case anyone still cares about this.

You have the arguments flipped in the wrong direction. It should be {{ default .Values.somekey false }}

That’s wrong. default takes the default value as its first argument, and the value to be tested as the second. I use this all the time. Yes, the order is weird, but the OP is right.

There’s a bug here and this needs to reopened.

I’m going to put this solution to my problem here in case it helps anyone:

I wanted to render part of a template (a deployment label) by default unless the values.yaml explicitly stated that a value was false:

      labels:
        {{- if ne false ((.Values.security).label).enabled }}
        myLabel: "this-section-is-rendered-unless-the-value-is-explicitly-false"
        {{- end }}

Here is the explanation of using the parenthesis on my evaluated value > https://stackoverflow.com/questions/59795596/how-to-make-nested-variables-optional-in-helm/68807258#68807258

And I am simply use a “not equals” which fits the logic very nicely. The users of my chart will have to explicitly state the specific value as false in order to not include this label in the deployment.

Hi @bacongobbler ,

What if I’d like to use this in a block if in my template? Something like:

{{- if (default $foo true) }}
someSetting: "bar"
{{- end }}

and I want the someSetting to not render only when $foo is explicitly set to false.

I do:

{{- if (dig "somekey" true .Values) }}
someSetting: bar
{{- end }}

Which looks in .Values for the key, “somekey”. If it’s there, it uses that value. If it’s not, it uses (in the above example) true as the default.

kcasas simplest workaround I’ve come up is this

list nil true | has .Values.vaultEnabled

In some cases it may be useful to also add the "true" string to the checked list

list nil true "true" | has .Values.vaultEnabled

A new issue to update the docs for the default function probably needs to be opened. It should contain a warning and as a recommended workaround I suggest something generic:

## this is always true if $defaults.enableIngress is true:
{{- if (default $defaults.enableIngress .enableIngress) }}

## replacement that works as expected:
{{- if (hasKey . "enableIngress" | ternary .enableIngress $defaults.enableIngress) }}

This is still open, istn’t it? The workaround provided by @bacongobbler does not seem to work. There must be some way to distinguish null from false? How else can you set a default to true and make it overridable by a false value?

@bacongobbler apologies, i noticed this too but it’s still incorrect the other way… I also tried {{ $deployment.enabled | default true }} just for the hell of it

values.yaml screen shot 2017-12-31 at 20 02 25

template: screen shot 2017-12-31 at 20 02 07

You would expect that to be false however:

screen shot 2017-12-31 at 20 01 47

Almost six years and it is still an issue. I want to explicitly change default-true in subchart in my values, and I cannot use false.

IMO the solution from @joejulian that is using the “dig” function is the most elegant, readable and simple solution.

Update: it is indeed mentioned in the documentation

How is this not re-opened or fixed? This is a really helpful thread with some workarounds, but we shouldn’t need it. This functionality with default and Booleans seems really simple and should work straight away

{{if ((.Values.health).enabled)}}

This works well for me, in case anyone still cares about this.

It works. But can you explain why the bracket can work it?

This whole thread is unbelievable. 4 years… 👎