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

  1. Raise the timeout in config: `timeout = "120s"` (hugo.toml) under the root.
  2. Identify and optimize the slow page (the page path is in the surrounding context).
  3. If a shortcode is looping, break the recursion.
  4. 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

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

Related errors


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)