gohugoio/hugo · critical

failed to build JS bundle

Error message

failed to build JS bundle: %w

What it means

Returned by the batch build path when esbuild's Build() call itself returns a non-nil error, as opposed to producing OutputFiles with errors attached. The wrapped error is the real esbuild failure (option validation, plugin Setup panic, or a hard build failure).

Solutions

  1. Inspect the wrapped error (the %w) — it is the actual cause; treat the outer message as a wrapper only.
  2. Reduce the batch to a single entrypoint to isolate which option triggers the failure.
  3. Verify the esbuild version bundled with your Hugo release against the option you are setting.
  4. If the wrapped error points to an internal Hugo plugin Setup issue, report it upstream with the unwrapped message.
Defensive patterns

Strategy: try-catch

Try / catch

Capture the error from Build(), then errors.Unwrap to log the underlying esbuild message separately from the Hugo wrapper. Distinguish a hard esbuild failure from per-file Errors before reporting.

Prevention

When it happens

Trigger: b.client.buildClient.Build(jsOpts) returns err != nil at batch.go:623-625. This is the synchronous failure path of esbuild itself, typically invalid option combinations or an internal Hugo plugin Setup callback that errored, rather than per-file syntax errors (those surface via result.Errors).

Common situations: Incompatible esbuild option combinations (e.g., Splitting without Format=esm); an outdated bundled esbuild version that rejects a configured option; a plugin Setup panic; very large builds exhausting memory.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/544e3cac5dd986b5. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/esbuild/batch.go:625

				}
				return nil
			},
			ResolveSourceMapSource: func(s string) string {
				if r, found := state.importResource.Get(s); found {
					if ss := resources.InternalResourceSourcePath(r); ss != "" {
						return ss
					}
					return PrefixHugoMemory + s
				}
				return ""
			},
			EntryPoints: entryPoints,
		},
	}

	result, err := b.client.buildClient.Build(jsOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to build JS bundle: %w", err)
	}

	groups := make(map[string]resource.Resources)

	createAndAddResource := func(targetPath, group string, o api.OutputFile, mt media.Type) error {
		var sourceFilename string
		if r, found := state.importResource.Get(targetPath); found {
			sourceFilename = resources.InternalResourceSourcePathBestEffort(r)
		}
		targetPath = path.Join(b.id, targetPath)

		rd := resources.ResourceSourceDescriptor{
			LazyPublish: true,
			OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
				return hugio.NewReadSeekerNoOpCloserFromBytes(o.Contents), nil
			},
			MediaType:            mt,
			TargetPath:           targetPath,

View on GitHub (pinned to 52c9bd7908)