Try/Catch, or other code to log variables to the console when transform.unmarshal fails

Thanks again for getting back to previous queries. Any progress on the following:

No movement, otherwise you’d see updates on the issue or associated PR. You might want to subscribe to both:

Is there a particular problem you’re trying to solve? It would be enlightening to see a failing test case where there is insufficient information to identify the problem.

Thanks, sounds good.

When I update more than one without the server running, or come back after doing some updates and not checking each one for any errors (all of which happen occasionally) , Hugo throws the transform unmarshall error but doesn’t specify which file contains the error.

At that point I have to reset the repo, and regenerate the files I added, to identify the source of the error, or open up each of the files and do syntax checking.

I try to think more competitively about it, but cannot make any promises :smile: I ask AI, though not a highly trained AI, as I’ve yet to install Claude or comparable, and you might find the responses entertaining, since they are fictional :smile: . Still, AI is already quite helpful with Hugo.

## Question Summary
The task is to modify the Hugo code snippet to ensure that if an error occurs during the `transform.Unmarshal` process, a message is logged to the console that includes the name of the file being processed.

Answer #1: Using Try-Catch Pattern

To handle errors effectively, you can utilize a try-catch pattern in Hugo. Although Hugo does not have a traditional try-catch mechanism, you can check for errors after the unmarshal operation. Here’s how you can implement it:

{{ $data := .Content | transform.Unmarshal }}
{{ if eq $data nil }}
  {{ printf "Error unmarshalling file: %s" .File.Path | warn }}
{{ end }}

Answer #2: Custom Error Handling Function

Another approach is to create a custom error handling function that can be reused across your templates. This function can log the error message along with the file name. Here’s a sample implementation:

{{ $data := .Content | transform.Unmarshal }}
{{ if .Params.error }}
  {{ logError .File.Path }}
{{ end }}

{{ $logError := (printf "Error unmarshalling file: %s" .File.Path) }}

The original code snippet you provided does not account for potential errors, which can lead to silent failures. By enhancing the code, we can ensure that any errors encountered during the unmarshalling process are logged appropriately.

Here’s how you can modify the code:

{{ $fileName := .File.Path }}
{{ $data, $err := .Content | transform.Unmarshal }}
{{ if $err }}
  {{ printf "Error unmarshalling file %s: %s" $fileName $err | warn }}
{{ end }}

My solution is to be more careful to ensure I’m generating the json files into the repo with the server on, or to syntax check the json file after it’s generated after modification, but Bep’s proposal was very on the mark.

I tested with a JSON file that was missing a closing bracket. As you stated, the error message does not identify the source of the file. That makes sense when passing a string (.e.g., .Content) to unmarshal, but it’s also true if you attempt to unmarshal the resource itself.

We could fix the latter, but try/catch is required for the former.

Also, this:

{{ with resources.Get $path }}
  {{ with . | transform.Unmarshal }}
    {{ $data = . }}
  {{ end }}
{{ else }}

Provides better performance[1] than this:

{{ with resources.Get $path }}
  {{ with .Content | transform.Unmarshal }}
    {{ $data = . }}
  {{ end }}
{{ else }}

The only time I’ve need the second construct is when a server returns an unexpected media type when using resoures.GetRemote.


  1. Hugo can stream the input stream instead of having to read it all into memory. ↩︎

In v0.141.0 you’ll be able to do this:

{{ range $r := resources.Match "**.json" }}
  {{ with try ($r | transform.Unmarshal) }}
    {{ with .Err }}
      {{ errorf ": %s: unable to unmarshal %s" . $r.Name }}
    {{ else with .Value }}
      {{ .name }}    <-- this is one of the fields in the data files
    {{ end }}
  {{ end }}
{{ end }}

That throws an error that tells you (a) the template and line number where the error occurred, and (b) the name of the file that could not be unmarshaled:

ERROR template: _default/home.html:24:29: executing “main” at <transform.Unmarshal>: error calling Unmarshal: “_stream.json:1:1”: unmarshal failed: unexpected end of JSON input: unable to unmarshal /data/b.json

In this example, data/b.json is invalid (missing closing bracket):

{
  "name": "Will"

1 Like

Awesome, just what the doctor ordered! Looking forward to the try/catch in v0.141.0 :+1: