gohugoio/hugo · error
invalid modules list: %q
Error message
invalid modules list: %q
What it means
When reading a vendor manifest (`_vendor/modules.txt`) in modules/collect.go:625, each non-empty line must have exactly two fields: `# <modulepath> <version>`. A line that trims to anything else fails parsing and Hugo aborts with `invalid modules list: %q`, naming the file. This protects against corrupted or hand-edited vendor metadata silently producing a wrong module set.
Source
Thrown at modules/collect.go:625
return err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
// # github.com/alecthomas/chroma v0.6.3
line := scanner.Text()
line = strings.Trim(line, "# ")
line = strings.TrimSpace(line)
if line == "" {
continue
}
parts := strings.Fields(line)
if len(parts) != 2 {
return fmt.Errorf("invalid modules list: %q", filename)
}
path := parts[0]
shouldAdd := c.Client.moduleConfig.VendorClosest
if !shouldAdd {
if _, found := c.vendored[path]; !found {
shouldAdd = true
}
}
if shouldAdd {
c.vendored[path] = vendoredModule{
Owner: owner,
Dir: filepath.Join(vendorDir, path),
Version: parts[1],
}
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Regenerate the vendor tree: delete `_vendor` (or fix modules.txt) and run `hugo mod vendor`.
- Open the named modules.txt and remove malformed lines/conflict markers — each line must be `# path version`.
- Resolve any git merge conflicts in `_vendor` by re-vendoring rather than hand-merging.
- Avoid manual edits to `_vendor/modules.txt`; treat it as generated output.
Example fix
# before (_vendor/modules.txt) # github.com/alecthomas/chroma <<<<<<< HEAD # after: regenerate rm -rf _vendor hugo mod vendor
Defensive patterns
Strategy: validation
Validate before calling
switch v := cfg.Get("module.imports").(type) {
case []interface{}, []map[string]interface{}:
// ok
default:
return fmt.Errorf("module.imports must be a list, got %T", v)
} Type guard
func isImportsList(v interface{}) bool {
_, ok := v.([]interface{})
return ok
} Prevention
- In TOML/YAML config, declare imports as an array of tables ([[module.imports]]), not a scalar or map
- Lint config files in CI with `hugo config` before building
- When generating config programmatically, marshal from typed structs rather than hand-built maps
When it happens
Trigger: `collector` parsing `_vendor/modules.txt` during collection when any line has fewer or more than two whitespace-separated fields after stripping the `# ` prefix — e.g. a module path with no version, extra tokens, or merge-conflict markers.
Common situations: Git merge conflicts leaving `<<<<<<<` markers inside `_vendor/modules.txt`; manual edits to the vendor manifest; line corruption from CRLF/encoding mangling; concatenated files from bad scripts.
Related errors
- %q not found
- error processing file %q
- failed to parse file %q: %s
- must not be run from the file system root
- failed to unmarshal config for path %q: %w
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/33cfe671439302da.json.
Report an issue: GitHub ↗.