Conditional shortcode with index - issue when no params are passed

I wrapped a shortcode implementation with the following conditional logic to support optional filtering out of content based on a Filters site params map and filter and filterval shortcode params:

{{- if or (not (.Get "filter")) (eq (.Get "filterval") (index $.Site.Params.Filters (.Get "filter"))) -}}
{{- end -}}

This works correctly when the shortcode is called with params — not necessarily the filter and filterval params, but any param. But if the shortcode is called without any params, I get a runtime error "error calling index: value is nil; should be of type string". I.e., when the shortcode is called without params, Hugo tries to check the index for an empty "filter" string. The same is true if I use a $filter shortcode variable and assign to it the value of .Get "filter".

I assume that I can work around this by breaking down the conditions and using Scratch, but I’d rather not. I don’t see why Hugo’s processing of the condition should differ depending on whether another, unrelated, shortcode param was set?!

(I’m using Hugo v0.30.2. I can’t test the latest version just yet because it requires replacing our current reliance on files.)

To prevent the evaluation of index if (.Get "filter") is returning nil, you should wrap that whole index in something like:

{{ with (.Get "filter") }}
    {{ index $.Site.Params.Filters . }}
{{ end }}

PS: I haven’t tried to fix the whole logic you have there… you might need to put an {{ else }} clause in that with and put something sensible in there to make the whole or logic work.

As I initially wrote, I assume I can fix it by breaking down the conditional logic, but I would prefer to have it in one “statement”. I’ve tried in the past to incorporate with within an if condition (not inside the true clause but as part of the condition) and wasn’t able to do it (not sure it’s supported, syntax wise).
Also, what puzzles me is that the same code works when I pass other params to the shortcode (that aren’t usd in the conditional statement), but doesn’t work when I don’t pass any params.

I would be surprised… Can you share the source of a minimal site that shows that that works? The with approach is the right one based on my experience.

I can’t share the full site but I can share a simple example of a shortcode and calls to this shortcode:

  1. Add a testshcd.html shortcode file:

    {{- if or (not (.Get "filter")) (eq (.Get "filterval") (index $.Site.Params.Filters (.Get "filter"))) -}} 
      Condition is TRUE
    {{- else -}}
      Condition is FALSE
    {{- end -}}
  2. Add a Filters site params map in config.toml:

    testtruefilter = "true"
    testfalsefilter = "false"
  3. Add these shortcode calls in any Markdown content file:

    Calling `testshcd` with `dummy="1"`: {{< testshcd dummy="1" >}}
    Calling `testshcd` with `filter="testtruefilter" filterval="true"`: {{< testshcd filter="testtruefilter" filterval="true" >}}
    Calling `testshcd` with `filter="filter" testtruefilter="false"`: {{< testshcd filter="testtruefilter" filterval="false" >}}
    Calling `testshcd` with `filter="testfalsefilter" filterval="true"`: {{< testshcd filter="testfalsefilter" filterval="true" >}}
    Calling `testshcd` with `filter="testfalsefilter" filterval="false"`: {{< testshcd filter="testfalsefilter" filterval="false" >}}

    The output is as expected — TRUE, TRUE, FALSE, FALSE, TRUE.

  4. Now, add a shortcode call without parameters at the start of the Markdown tests:

    Calling `testshcd` without params: {{< testshcd >}}

    This results in the following runtime error: "error calling index: value is nil; should be of type string".

As you can see, the evaluation of the condition behaves differently when you pass any parametre to the shortcode (even an unused dummy parameter that’s not related to the filter logic) and when you don’t pass any parameters to the shortcode. In my opinion, this shouldn’t happen.