gohugoio/hugo · error
invalid loader
Error message
invalid loader: %q
What it means
Thrown when a value in the Loaders map (mapping file extensions to loaders) is not one of the supported loader names in nameLoader. Loaders configure how esbuild treats a given file extension.
Solutions
- Use a supported loader name: none, base64, binary, copy, css, dataurl, default, empty, file, global-css, js, json, jsx, local-css, text, ts, tsx.
Example fix
// before
{{ $opts := dict "loaders" (dict ".png" "image") }}
// after
{{ $opts := dict "loaders" (dict ".png" "dataurl") }} Defensive patterns
Strategy: validation
Validate before calling
validLoaders := map[string]bool{"none": true, "base64": true, "binary": true, "copy": true, "css": true, "dataurl": true, "default": true, "empty": true, "file": true, "global-css": true, "js": true, "json": true, "jsx": true, "local-css": true, "text": true, "ts": true, "tsx": true}
for ext, l := range opts.Loaders {
if !validLoaders[l] {
return fmt.Errorf("invalid loader %q for extension %q", l, ext)
}
} Prevention
- Cross-check loader names against esbuild's documented list.
- Lowercase all loader values before validation.
- Reject unknown loader names at config load.
When it happens
Trigger: Setting Loaders: {".png": "image"} where "image" is not a known loader name. The lookup at options.go:316 fails and the invalid value is reported.
Common situations: User invents loader names; copy-paste from esbuild docs with a typo; case mismatch — loaders are lowercase, so "JS" or "DataURL" won't match.
Related errors
- invalid engine version
- unsupported drop type
- unsupported jsx type
- unsupported platform type
- unsupported script output format
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/3832fc16e4f4308e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/esbuild/options.go:318
target = api.ESNext
}
var loaders map[string]api.Loader
if opts.IsCSS {
loaders = make(map[string]api.Loader)
// Add default CSS file loaders.
// May be overridden by opts.Loaders.
maps.Copy(loaders, extensionToLoaderMapCSS)
}
if opts.Loaders != nil {
if loaders == nil {
loaders = make(map[string]api.Loader)
}
for k, v := range opts.Loaders {
loader, found := nameLoader[v]
if !found {
err = fmt.Errorf("invalid loader: %q", v)
return
}
loaders[k] = loader
}
}
mediaType := opts.MediaType
if mediaType.IsZero() {
mediaType = media.Builtin.JavascriptType
}
var loader api.Loader
switch mediaType.SubType {
case media.Builtin.JavascriptType.SubType:
loader = api.LoaderJS
case media.Builtin.TypeScriptType.SubType:
loader = api.LoaderTS
case media.Builtin.TSXType.SubType:View on GitHub (pinned to 52c9bd7908)