Skip to content

Commit 0579afc

Browse files
committed
Fix "assignment to entry in nil map" on empty YAML config files
Fixes #14074
1 parent 0ccbc63 commit 0579afc

File tree

5 files changed

+67
-9
lines changed

5 files changed

+67
-9
lines changed

‎common/herrors/errors.go‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,13 @@ package herrors
1717
import (
1818
"errors"
1919
"fmt"
20-
"io"
2120
"os"
2221
"regexp"
23-
"runtime"
2422
"runtime/debug"
2523
"strings"
2624
"time"
2725
)
2826

29-
// PrintStackTrace prints the current stacktrace to w.
30-
func PrintStackTrace(w io.Writer) {
31-
buf := make([]byte, 1<<16)
32-
runtime.Stack(buf, true)
33-
fmt.Fprintf(w, "%s", buf)
34-
}
35-
3627
// ErrorSender is a, typically, non-blocking error handler.
3728
type ErrorSender interface {
3829
SendError(err error)

‎config/allconfig/load.go‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020
"os"
2121
"path/filepath"
22+
"runtime/debug"
2223
"strings"
2324

2425
"github.com/gobwas/glob"
@@ -44,6 +45,7 @@ func LoadConfig(d ConfigSourceDescriptor) (configs *Configs, err error) {
4445
defer func() {
4546
if r := recover(); r != nil {
4647
err = fmt.Errorf("failed to load config: %v", r)
48+
debug.PrintStack()
4749
}
4850
}()
4951

‎hugolib/config_test.go‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,3 +1649,16 @@ Params: {{ site.Params }}|
16491649

16501650
}
16511651
}
1652+
1653+
func TestConfigYAMLNilMapIssue14074(t *testing.T) {
1654+
t.Parallel()
1655+
1656+
files := `
1657+
-- config/_default/taxonomies.yaml --
1658+
# empty on purpose
1659+
-- hugo.yaml --
1660+
1661+
`
1662+
1663+
Test(t, files)
1664+
}

‎parser/metadecoders/decoder.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ func (d Decoder) UnmarshalToMap(data []byte, f Format) (map[string]any, error) {
8686

8787
err := d.UnmarshalTo(data, f, &m)
8888

89+
if m == nil {
90+
// We migrated to github.com/goccy/go-yaml in v0.152.0,
91+
// which produces nil maps for empty YAML files (and empty map nodes), unlike gopkg.in/yaml.v2.
92+
//
93+
// To prevent crashes when trying to handle empty config files etc., we ensure we always return a non-nil map here.
94+
// See issue 14074.
95+
m = make(map[string]any)
96+
}
97+
8998
return m, err
9099
}
91100

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2025 The Hugo Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package metadecoders_test
15+
16+
import (
17+
"testing"
18+
19+
"github.com/gohugoio/hugo/hugolib"
20+
)
21+
22+
func TestYAMLIntegerSortIssue14078(t *testing.T) {
23+
files := `
24+
-- assets/mydata.yaml --
25+
a:
26+
weight: 1
27+
x:
28+
weight: 2
29+
c:
30+
weight: 3
31+
t:
32+
weight: 4
33+
34+
-- layouts/all.html --
35+
{{ $mydata := resources.Get "mydata.yaml" | transform.Unmarshal }}
36+
Sorted: {{ sort $mydata "weight" }}|
37+
38+
`
39+
40+
b := hugolib.Test(t, files)
41+
42+
b.AssertFileContent("public/index.html", "Sorted: [map[weight:1] map[weight:2] map[weight:3] map[weight:4]]|")
43+
}

0 commit comments

Comments
 (0)