gohugoio/hugo · error
failed to download module %s@%s: %s: %s
Error message
failed to download module %s@%s: %s: %s
What it means
Returned by downloadModuleVersion when `go mod download -json path@version` fails and Go emitted a JSON error payload on stdout. Hugo extracts the detailed message from that JSON and appends it to the process error so the user sees the real cause (e.g. unknown revision) rather than just an exit status.
Source
Thrown at modules/client.go:464
if b, _ := c.ccfg.ModuleQueriesCache.GetBytes(cacheKey); len(b) > 0 {
var cm goModule
if err := json.Unmarshal(b, &cm); err == nil && cm.Dir != "" {
if c.isDirNonEmpty(cm.Dir) {
return &cm, nil
}
}
}
// No valid cache, need to query.
args := []string{"mod", "download", "-json", fmt.Sprintf("%s@%s", path, version)}
b := &bytes.Buffer{}
err := c.runGo(context.Background(), b, args...)
if err != nil {
// The -json flag makes Go output error details as JSON to stdout
// even on failure. Try to extract the error message from the JSON output.
if jsonErr := extractGoModDownloadError(b.Bytes()); jsonErr != "" {
return nil, fmt.Errorf("failed to download module %s@%s: %s: %s", path, version, err, jsonErr)
}
return nil, fmt.Errorf("failed to download module %s@%s: %w", path, version, err)
}
jsonResult := b.Bytes()
m := &goModule{}
if err := json.NewDecoder(bytes.NewReader(jsonResult)).Decode(m); err != nil {
return nil, fmt.Errorf("failed to decode module download result: %w", err)
}
if m.Error != nil {
return nil, errors.New(m.Error.Err)
}
// Cache the successful result if it has a Dir field.
if m.Dir != "" {
_ = c.ccfg.ModuleQueriesCache.SetBytes(cacheKey, jsonResult)View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Read the appended Go error message — fix the version or tag named in your module import config.
- Check available versions with `go list -m -versions <path>`.
- For private modules set GOPRIVATE and GONOSUMDB appropriately.
- Run `hugo mod clean` and retry to rule out a corrupt cache.
Example fix
# hugo.toml before [[module.imports]] path = "github.com/user/theme" version = "v9.9.9" # after version = "v1.4.2"
Defensive patterns
Strategy: retry
Try / catch
var lastErr error
for attempt := 0; attempt < 3; attempt++ {
if err := client.Download(mod); err != nil {
lastErr = err
if isNetworkErr(err) { time.Sleep(backoff(attempt)); continue }
return err // non-transient: bad version, checksum, etc.
}
return nil
}
return lastErr Prevention
- Retry only transient network/proxy failures with exponential backoff; fail fast on version-not-found
- Configure GOPROXY with a fallback (e.g. 'https://proxy.golang.org,direct')
- Warm the module cache in CI (cache $GOMODCACHE) so downloads rarely hit the network
- Inspect the embedded stderr text to distinguish auth failures (private repos need GOPRIVATE/credentials) from flaky network
When it happens
Trigger: Downloading a specific module version (e.g. resolving a theme import or version query) where `go mod download -json` exits non-zero but writes a JSON object with an Error field: unknown revision/tag, module path not found, or checksum database rejection.
Common situations: Theme config in hugo.toml pinning a version/tag that was deleted or never existed, module repo renamed or made private, GONOSUMDB/GONOSUMCHECK issues with the sum database.
Related errors
- failed to download module %s@%s: %w
- failed to download modules: %w
- failed to get %q: %w
- failed to init modules: %w
- failed to decode module download result: %w
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/6e5432998c86de19.json.
Report an issue: GitHub ↗.