gohugoio/hugo · error
timed out rendering the page content. Extend the `timeout`…
Error message
timed out rendering the page content. Extend the `timeout` limit in your Hugo config file: %w
What it means
Returned from the plain-summary/word-count computation (page__content.go:825) when the page-content render step was killed by Hugo's timeout and the error is recognized as a timeout (herrors.IsTimeoutError). It tells the author that rendering the page exceeded the configured `timeout` and that the limit is raised in config rather than in code.
Solutions
- Raise the timeout in config: `timeout = "120s"` (hugo.toml) under the root.
- Identify and optimize the slow page (the page path is in the surrounding context).
- If a shortcode is looping, break the recursion.
- For external converters, ensure they start fast (cold-start penalty) or pre-warm them.
Example fix
// before (hugo.toml) timeout = "30s" // after timeout = "120s"
Defensive patterns
Strategy: validation
Validate before calling
// library use: set a timeout proportional to your largest page // cfg.Timeout = 2 * time.Minute (or hugo.toml: timeout = "120s")
Try / catch
if err := pageContent(); err != nil {
var te interface{ Timeout() bool }
if errors.As(err, &te) && te.Timeout() { /* raise limit / optimize page */ }
} Prevention
- Set `timeout` generously for large math-heavy sites.
- Profile slow pages and cache expensive transforms.
- Avoid near-recursive shortcodes.
When it happens
Trigger: Rendering a page's content (including shortcode expansion and the content converter) takes longer than the configured timeout. Common with heavy math rendering, very large pages, recursive/looping shortcodes, or a slow external markup converter called inside the page.
Common situations: A page with hundreds of LaTeX blocks via transform.ToMath; an accidental near-infinite shortcode loop; an external converter (pandoc/asciidoctor) hanging; a watchdog too tight for a large corpus.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- failed to parse timeout
- --appendPort=false not supported when in multihost mode
- cache dir contains unresolved placeholders
- cannot convert to time.Duration
- cannot determine BaseURL for protocol
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/3f03c40c102ebdce.
Report an issue: GitHub.
Appendix: source
Thrown at hugolib/page__content.go:825
// TODO(bep) is set in a test. Fix that.
if result.fuzzyWordCount == 0 {
result.fuzzyWordCount = (result.wordCount + 100) / 100 * 100
}
if isCJKLanguage {
result.readingTime = (result.wordCount + 500) / 501
} else {
result.readingTime = (result.wordCount + 212) / 213
}
rs.Value = result
return rs, nil
})
if err != nil {
if herrors.IsTimeoutError(err) {
err = fmt.Errorf("timed out rendering the page content. Extend the `timeout` limit in your Hugo config file: %w", err)
}
return contentPlainPlainWords{}, err
}
return v.Value, nil
}
type cachedContentScope struct {
*cachedContent
pco *pageContentOutput
scope string
}
func (c *cachedContentScope) prepareContext(ctx context.Context) context.Context {
// A regular page's shortcode etc. may be rendered by e.g. the home page,
// so we need to track any changes to this content's page.
ctx = tpl.Context.DependencyManagerScopedProvider.Set(ctx, c.pco.po.p)
// The markup scope is recursive, so if already set to a non zero value, preserve that value.View on GitHub (pinned to 52c9bd7908)