Repository: gohugoio/hugo (language: go)

Issue:
Hugo crashes when adding invalid data file to data directory.
<!-- Please answer these questions before submitting your issue. Thanks! -->

### What version of Hugo are you using (`hugo version`)?

<pre>
$ hugo version
hugo v0.83.1-5AFE0A57 windows/amd64 BuildDate=2021-05-02T14:38:05Z VendorInfo=gohugoio
</pre>

### Does this issue reproduce with the latest release?
Yes.

Hugo server crashes when:
1. You use JSON files in your data directory
2. AND you add a new 0 byte JSON file, or change one of the JSON files to 0 bytes

When you add a new 0 byte file, you don't even have to reference it in your code. I think Hugo is evaluating it for validity.

I've gone over this on the Hugo discourse page with another: https://discourse.gohugo.io/t/hugo-crashes-when-theres-a-data-file-with-no-data-in-it/33189/4


Discussion / hints:
Hey, I've made a PR for this issue [here](https://github.com/gohugoio/hugo/pull/8603). Looking for feedback.

P.S It's my first contribution here.
Can I work on this @bep? I am new to OSS and want to try this out. Thanks
@bep, Is this issue still upforgrabs?
@bep, is this issue still relevant?
If yes, then I'd like to work on this issue

Fix patch:
diff --git a/parser/metadecoders/decoder.go b/parser/metadecoders/decoder.go
index 3db0ae338f6..3f322ad92e4 100644
--- a/parser/metadecoders/decoder.go
+++ b/parser/metadecoders/decoder.go
@@ -112,7 +112,7 @@ func (d Decoder) UnmarshalStringTo(data string, typ any) (any, error) {
 // Unmarshal will unmarshall data in format f into an interface{}.
 // This is what's needed for Hugo's /data handling.
 func (d Decoder) Unmarshal(data []byte, f Format) (any, error) {
-	if data == nil {
+	if len(data) == 0 {
 		switch f {
 		case CSV:
 			return make([][]string, 0), nil


Test patch:
diff --git a/parser/metadecoders/decoder_test.go b/parser/metadecoders/decoder_test.go
index 7b762667c10..5e917beffbf 100644
--- a/parser/metadecoders/decoder_test.go
+++ b/parser/metadecoders/decoder_test.go
@@ -116,21 +116,23 @@ func TestUnmarshalToInterface(t *testing.T) {
 	d := Default
 
 	for i, test := range []struct {
-		data   string
+		data   []byte
 		format Format
 		expect any
 	}{
-		{`[ "Brecker", "Blake", "Redman" ]`, JSON, []any{"Brecker", "Blake", "Redman"}},
-		{`{ "a": "b" }`, JSON, expect},
-		{`#+a: b`, ORG, expect},
-		{`#+DATE: <2020-06-26 Fri>`, ORG, map[string]any{"date": "2020-06-26"}},
-		{`a = "b"`, TOML, expect},
-		{`a: "b"`, YAML, expect},
-		{`<root><a>b</a></root>`, XML, expect},
-		{`a,b,c`, CSV, [][]string{{"a", "b", "c"}}},
-		{"a: Easy!\nb:\n  c: 2\n  d: [3, 4]", YAML, map[string]any{"a": "Easy!", "b": map[string]any{"c": 2, "d": []any{3, 4}}}},
+		{[]byte(`[ "Brecker", "Blake", "Redman" ]`), JSON, []any{"Brecker", "Blake", "Redman"}},
+		{[]byte(`{ "a": "b" }`), JSON, expect},
+		{[]byte(``), JSON, map[string]any{}},
+		{[]byte(nil), JSON, map[string]any{}},
+		{[]byte(`#+a: b`), ORG, expect},
+		{[]byte(`#+DATE: <2020-06-26 Fri>`), ORG, map[string]any{"date": "2020-06-26"}},
+		{[]byte(`a = "b"`), TOML, expect},
+		{[]byte(`a: "b"`), YAML, expect},
+		{[]byte(`<root><a>b</a></root>`), XML, expect},
+		{[]byte(`a,b,c`), CSV, [][]string{{"a", "b", "c"}}},
+		{[]byte("a: Easy!\nb:\n  c: 2\n  d: [3, 4]"), YAML, map[string]any{"a": "Easy!", "b": map[string]any{"c": 2, "d": []any{3, 4}}}},
 		// errors
-		{`a = "`, TOML, false},
+		{[]byte(`a = "`), TOML, false},
 	} {
 		msg := qt.Commentf("%d: %s", i, test.format)
 		m, err := d.Unmarshal([]byte(test.data), test.format)