gohugoio/hugo · error
failed to read page content
Error message
failed to read page content: %w
What it means
Returned by pageparser.ParseFrontMatterAndContent when io.ReadAll fails to consume the provided io.Reader. This wraps the underlying I/O error (e.g. a broken pipe, premature close, or failed network read) with %w so callers can unwrap it. The function reads the entire content stream into memory before lexing front matter, so any read fault anywhere in the stream surfaces here.
Solutions
- Verify the io.Reader is fully readable before passing it in (e.g. buffer it with a bytes.Buffer or io.ReadAll upstream and handle errors there).
- If reading from a file, check file permissions, that the file is not being written/rotated concurrently, and that it is not truncated.
- Unwrap the error with errors.Is/errors.As to distinguish a transient I/O fault from a permanent one and decide whether to retry the read.
Example fix
// before
r := openUnreliableReader()
cf, err := pageparser.ParseFrontMatterAndContent(r)
if err != nil { return err }
// after: buffer first so read errors surface explicitly
buf, err := io.ReadAll(openUnreliableReader())
if err != nil { return fmt.Errorf("prefetch content: %w", err) }
cf, err := pageparser.ParseFrontMatterAndContent(bytes.NewReader(buf))
if err != nil { return err } Defensive patterns
Strategy: validation
Validate before calling
// Pre-buffer the reader so parse errors are decoupled from read errors.
func safeParse(r io.Reader) (pageparser.ContentFrontMatter, error) {
b, err := io.ReadAll(r)
if err != nil {
return pageparser.ContentFrontMatter{}, fmt.Errorf("prefetch content: %w", err)
}
if len(b) == 0 {
return pageparser.ContentFrontMatter{}, errors.New("empty content input")
}
return pageparser.ParseFrontMatterAndContent(bytes.NewReader(b))
} Try / catch
if cf, err := pageparser.ParseFrontMatterAndContent(r); err != nil {
var pathErr *fs.PathError
if errors.As(err, &pathErr) { /* handle file-level fault */ }
return err
} else { use(cf) } Prevention
- Buffer untrusted/streaming readers into a []byte before calling parse functions.
- Never pass a reader that may be closed concurrently.
- Log the unwrapped error to distinguish read faults from parse faults.
When it happens
Trigger: Calling pageparser.ParseFrontMatterAndContent(r) where r is an io.Reader whose Read returns an error before EOF -- e.g. a bytes.Reader that's fine, but a network-backed reader, a gzip.Reader on truncated data, or a file Reader on a disk that hits an I/O error mid-read.
Common situations: Content served over an unreliable stream, a content file that is concurrently truncated/rotated, a reader wrapping a tar/gzip stream that ends unexpectedly, or a custom io.Reader implementation that returns an error instead of io.EOF.
Related errors
- alias "" is an empty string
- alias " " resolves to website root directory
- [ ] Error reading blob data (size: %llu read: %zu) \n
- [ ] Error reading blob data (size: %llu read: %zu) \n
- data: failed to open
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/4b79777d306e18a9.
Report an issue: GitHub.
Appendix: source
Thrown at parser/pageparser/pageparser.go:63
return nil, err
}
return l.items, l.err
}
type ContentFrontMatter struct {
Content []byte
FrontMatter map[string]any
FrontMatterFormat metadecoders.Format
}
// ParseFrontMatterAndContent is a convenience method to extract front matter
// and content from a content page.
func ParseFrontMatterAndContent(r io.Reader) (ContentFrontMatter, error) {
var cf ContentFrontMatter
input, err := io.ReadAll(r)
if err != nil {
return cf, fmt.Errorf("failed to read page content: %w", err)
}
psr, err := ParseBytes(input, Config{})
if err != nil {
return cf, err
}
var frontMatterSource []byte
iter := NewIterator(psr)
walkFn := func(item Item) bool {
if frontMatterSource != nil {
// The rest is content.
cf.Content = input[item.low:]
// Done
return false
} else if item.IsFrontMatter() {View on GitHub (pinned to 52c9bd7908)