Nil pointer evaluating resource.Resource.RelPermalink when using resources.Copy

Hi,

There seems to be a sort of regression in the latest Hugo (I’m not sure if extractly 0.124 or later. But it’s not there in 0.123.8) but I want to double check I’m not doing anything stupid.

In one of the layouts I have the following code (warnf added to debug

  {{ warnf "%[1]v %[2]v" $img (path.Join .Page.RelPermalink "og.png") }}
  {{ $img = resources.Copy (path.Join .Page.RelPermalink "og.png") $img }}
  {{ warnf "%[1]v %[2]v" $img .Permalink}} 

With all pages, it went just fine with 0.123.8.

But one page is failing with the latest Hugo. I’m getting this in the build “logs”:

WARN  /og_base.png /2024/open-graph-hugo/
WARN  <nil> https://blog.lanzani.nl/2024/open-graph-hugo/
[...]
Error: error building site: render: failed to render pages: render of "page" failed: "..../themes/hugola/layouts/_default/single.html:1:3": execute of template failed: template: _default/single.html:1:3: executing "_default/single.html" at <partial "header.html" .>: error calling partial: 
".../themes/hugola/layouts/partials/header.html:7:7": execute of template failed: template: partials/header.html:7:7: executing "partials/header.html" at <partial "opengraph.html" .>: error calling partial: 
".../themes/hugola/layouts/partials/opengraph.html:81:43": execute of template failed: template: partials/opengraph.html:81:43: executing "partials/opengraph.html" at <$img.Permalink>: nil pointer evaluating resource.Resource.Permalink

So basically $img is set (first line), but it becomes nil when doing the resources.Copy,

The fact it only fails with one page is fishy. I’ve reverted to 0.123.8, and everything is OK.

Thoughts?

Is $img a global resource or a page resource?

Hi,

It’s defined in the same template

  {{ $base := resources.Get "og_standard.png" }}
  {{ if fileExists "assets/og_base.png"}}
    {{ $base = resources.Get "og_base.png" }}
  {{ end }}

  {{ $img := $base.Filter (images.Text .Page.Title (dict
    "color" "#eceef0"
    "size" 52
    "linespacing" 2
    "x" 65
    "y" 50
  ))}}

So, to answer my question, $img is a global asset that has been passed through the images.Text filter.

I’ll try to look into this later today.

Also, it would save a lot of time if you were to share your repository.

Sure, it’s still a mess as I haven’t really had time to properly do it the Hugo way since moving from Jekyll (I’m actually refactoring it ATM).

Here’s what I did:

hugo new site hugo-forum-topic-49030
cd hugo-forum-topic-49030/
git init
git submodule add https://github.com/gglanzani/hugola themes/hugola
echo "theme = 'hugola'" >> hugo.toml
hugo new posts/post-1.md
hugo server -D

Here’s what I got:

Start building sites … 
hugo v0.124.1-db083b05f16c945fec04f745f0ca8640560cf1ec+extended linux/amd64 BuildDate=2024-03-20T11:40:10Z VendorInfo=gohugoio


                   | EN  
-------------------+-----
  Pages            | 10  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     | 12  
  Processed images |  4  
  Aliases          |  1  
  Cleaned          |  0  

Built in 19 ms

No error.


EDIT: Rested with v0.124.1 and got the same result. Updated console output shown above.

Hi Joe,

Almost all pages (I have 100 blog posts), render OK in my case as well (full repo is at GitHub - gglanzani/blog.lanzani.nl: My blog)

But one is messed up (open-graph-hugo/) and trips the latest hugo.

If I remove the offending page, all is well.

What is the file path to the above?

content/posts/2024-03-14-automatically-add-images-for-opengraph.md

Weird. Behavior started with v0.124.0.

If I change this:

url: /2024/open-graph-hugo

to this:

url: /2024/xopen-graph-hugo

…there are no errors.

Hi Joe,

I guess I’ll let you investigate in the meantime? I can change the url, but I’d rather stay on 0.123.8 :slight_smile:

This also works fine:

url: /2024/opengraph-hugo

which is probably a better URL anyway because opengraph is one word.

Yes, I’ll investigate.


Investigation notes

1) This works too (changing the year):

url: /2023/open-graph-hugo

2) No errors if I remove this line from content:

{{< figure src="/2024/open-graph-hugo/og.png" width="90%" >}}

3) We (I) changed the figure shortcode in v0.124.0 to handle multilingual single-host sites in their default configuration where page resources are not duplicated to each language. If I use the v0.123.8 version of the shortcode there are no problems:

themes/hugola/layouts/shortcodes/figure.html
<figure{{ with .Get "class" }} class="{{ . }}"{{ end }}>
    {{- if .Get "link" -}}
        <a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>
    {{- end -}}
    <img src="{{ .Get "src" }}"
         {{- if or (.Get "alt") (.Get "caption") }}
         alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
         {{- end -}}
         {{- with .Get "width" }} width="{{ . }}"{{ end -}}
         {{- with .Get "height" }} height="{{ . }}"{{ end -}}
         {{- with .Get "loading" }} loading="{{ . }}"{{ end -}}
    /><!-- Closing img tag -->
    {{- if .Get "link" }}</a>{{ end -}}
    {{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
        <figcaption>
            {{ with (.Get "title") -}}
                <h4>{{ . }}</h4>
            {{- end -}}
            {{- if or (.Get "caption") (.Get "attr") -}}<p>
                {{- .Get "caption" | markdownify -}}
                {{- with .Get "attrlink" }}
                    <a href="{{ . }}">
                {{- end -}}
                {{- .Get "attr" | markdownify -}}
                {{- if .Get "attrlink" }}</a>{{ end }}</p>
            {{- end }}
        </figcaption>
    {{- end }}
</figure>

4) I can fix this by replacing this:

{{ $img = resources.Copy (path.Join .Page.RelPermalink "og.png") $img }}

with this:

{{ $img = resources.Copy (path.Join "xxx" "og.png") $img }}

So, there’s something about calling the page’s .RelPermalink method, in conjunction with the shortcode call, that’s triggering this. Or, perhaps more likely, it’s triggered by copying the resource to that particular path.

5) Using the new shortcode with an older version of Hugo still throws an error, so this is an old (interference) bug.

6) I can eliminate the error by modifying the shortcode, changing this:

 {{- with or (.Page.Resources.Get $u.Path) (resources.Get $u.Path) -}}

to this:

 {{- with or (.Page.Resources.Get $u.Path) -}}

7) Maybe related to https://github.com/gohugoio/hugo/issues/10412?

8) The call to .Content in opengraph.html causes the page to be rendered, including the shortcode that publishes the resource. If you remove .Content from opengraph.html there are no errors.

9) Minimal reproducible example:

git clone --single-branch -b hugo-forum-topic-49030 https://github.com/jmooring/hugo-testing hugo-forum-topic-49030
cd hugo-forum-topic-49030
hugo

10) Per the above, this isn’t a regression. The revised figure shortcode introduced in v0.124.0 exposes a previously masked problem that occurs with this unusual shortcode+partial construct. Not sure if this is a bug because it is difficult to think through the rendering sequence.

@lanzani

I’ve logged an issue for this, #12310, but I doubt it will be addressed anytime in the near future. Hugo has behaved this way for a long time; recent changes to the figure shortcode exposed this behavior. And I’m not sure if the issue I logged is a bug report or an enhancement request. Your shortcode+partial construct is… unexpected.

From where I’m sitting you have two options:

  1. Remove the .Content call from your opengraph partial, using the text in front matter without falling back.

  2. Override the embedded figure shortcode, removing the fallback to check for a global resource as shown below:

layouts/shortcodes/figure.html
<figure{{ with .Get "class" }} class="{{ . }}"{{ end }}>
  {{- if .Get "link" -}}
    <a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>
  {{- end -}}

  {{- $u := urls.Parse (.Get "src") -}}
  {{- $src := $u.String -}}
  {{- if not $u.IsAbs -}}
    {{- with or (.Page.Resources.Get $u.Path) -}}
      {{- $src = .RelPermalink -}}
    {{- end -}}
  {{- end -}}

  <img src="{{ $src }}"
    {{- if or (.Get "alt") (.Get "caption") }}
    alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
    {{- end -}}
    {{- with .Get "width" }} width="{{ . }}"{{ end -}}
    {{- with .Get "height" }} height="{{ . }}"{{ end -}}
    {{- with .Get "loading" }} loading="{{ . }}"{{ end -}}
  ><!-- Closing img tag -->
  {{- if .Get "link" }}</a>{{ end -}}
  {{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
    <figcaption>
      {{ with (.Get "title") -}}
        <h4>{{ . }}</h4>
      {{- end -}}
      {{- if or (.Get "caption") (.Get "attr") -}}<p>
        {{- .Get "caption" | markdownify -}}
        {{- with .Get "attrlink" }}
          <a href="{{ . }}">
        {{- end -}}
        {{- .Get "attr" | markdownify -}}
        {{- if .Get "attrlink" }}</a>{{ end }}</p>
      {{- end }}
    </figcaption>
  {{- end }}
</figure>

Hi Joe,

Thanks for the update and the workaround.

While I definitely think it’s a bug (why should path.Join return a nil?), I’ve applied your workaround by overwriting the figure shortcode (and changing the url) and all is well :slight_smile:

Thanks a lot!

I’m glad everything’s working for you.

path.Join is not the problem. The minimal example and test case hardcode the path.

My best guess is that the shortcode is trying to capture a global asset “foo” when you call .Content, and we cache the nil result. Then you call resources.Copy to “foo”, but we don’t copy to “foo” because “foo” already exists (as nil) in the cache. Or something like that.

That’s a WAG, but would make sense.

This has been fixed and will be available in the next release.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.