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

  1. Read the appended Go error message — fix the version or tag named in your module import config.
  2. Check available versions with `go list -m -versions <path>`.
  3. For private modules set GOPRIVATE and GONOSUMDB appropriately.
  4. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/6e5432998c86de19.json. Report an issue: GitHub ↗.