{"record":{"id":"6e5432998c86de19","repo":"gohugoio/hugo","slug":"failed-to-download-module-s-s-s-s","errorCode":null,"errorMessage":"failed to download module %s@%s: %s: %s","messagePattern":"failed to download module (.+?)@(.+?): (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/client.go","lineNumber":464,"sourceCode":"\tif b, _ := c.ccfg.ModuleQueriesCache.GetBytes(cacheKey); len(b) > 0 {\n\t\tvar cm goModule\n\t\tif err := json.Unmarshal(b, &cm); err == nil && cm.Dir != \"\" {\n\t\t\tif c.isDirNonEmpty(cm.Dir) {\n\t\t\t\treturn &cm, nil\n\t\t\t}\n\t\t}\n\t}\n\n\t// No valid cache, need to query.\n\targs := []string{\"mod\", \"download\", \"-json\", fmt.Sprintf(\"%s@%s\", path, version)}\n\n\tb := &bytes.Buffer{}\n\terr := c.runGo(context.Background(), b, args...)\n\tif err != nil {\n\t\t// The -json flag makes Go output error details as JSON to stdout\n\t\t// even on failure. Try to extract the error message from the JSON output.\n\t\tif jsonErr := extractGoModDownloadError(b.Bytes()); jsonErr != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"failed to download module %s@%s: %s: %s\", path, version, err, jsonErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to download module %s@%s: %w\", path, version, err)\n\t}\n\n\tjsonResult := b.Bytes()\n\n\tm := &goModule{}\n\tif err := json.NewDecoder(bytes.NewReader(jsonResult)).Decode(m); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode module download result: %w\", err)\n\t}\n\n\tif m.Error != nil {\n\t\treturn nil, errors.New(m.Error.Err)\n\t}\n\n\t// Cache the successful result if it has a Dir field.\n\tif m.Dir != \"\" {\n\t\t_ = c.ccfg.ModuleQueriesCache.SetBytes(cacheKey, jsonResult)","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/modules/client.go#L446-L482","documentation":"Thrown by downloadModuleVersion after `go mod download -json path@version` exits non-zero. Hugo asks Go for structured error output via the -json flag and extractGoModDownloadError pulls the `Error` field out of the JSON; this variant is used when that extraction succeeds, so the message carries both the raw go-command error and the parsed JSON error (typically the real cause: 404, dial, 410 gone, sum mismatch, auth). It means the module fetch genuinely failed at the Go toolchain level, not a Hugo-side bug.","triggerScenarios":"A module import in hugo.toml/go.mod with an explicit version (e.g. `[[module.imports]] path=\"github.com/x/y\" version=\"v1.2.3\"`) where `go mod download -json github.com/x/y@v1.2.3` fails and its JSON output contains an Error object. Happens on first build, after `hugo mod clean`, or when the GOPROXY/GONOSUMCHECK setup can't reach the proxy.","commonSituations":"Private repo without GOPRIVATE set (proxy returns 404/410), module deleted or force-pushed away (unknown revision), version tag yanked, corporate proxy/firewall blocking proxy.golang.org, GOFLAGS=-mod=vendor conflict, or a typo'd module path that resolves to a real 404 from the proxy.","solutions":["Inspect the embedded JSON error (second %s) — for '404/410 Gone' confirm the module path and tag exist on the remote; for 'unknown revision' edit go.mod to a valid branch/tag.","For private modules set GOPRIVATE and check GOPROXY: `go env -w GOPRIVATE=github.com/yourorg/*` and verify `go mod download path@version` works outside Hugo.","Clear the module cache and retry: `go clean -modcache && hugo mod clean` then rebuild.","If the proxy is unreachable, configure a working GOPROXY (e.g. company mirror) or set GONOSUMCHECK/GONOSUMDB appropriately for private checksums."],"exampleFix":"// before (hugo.toml)\n[module]\n[[module.imports]]\npath = \"github.com/myorg/secret-theme\"\nversion = \"v1.0.0\"\n\n// after: tell the toolchain the module is private + reachable\ngo env -w GOPRIVATE=github.com/myorg/*\ngo env -w GOPROXY=https://goproxy.company.io,direct","handlingStrategy":"validation","validationCode":"// Validate reachability + privacy before letting Hugo download\nimport \"os/exec\"\n\nfunc checkModuleFetchable(path, version string) error {\n  // 1. go binary present\n  if _, err := exec.LookPath(\"go\"); err != nil {\n    return fmt.Errorf(\"go toolchain missing: %w\", err)\n  }\n  // 2. reproducible probe\n  cmd := exec.Command(\"go\", \"mod\", \"download\", \"-json\", path+\"@\"+version)\n  out, err := cmd.CombinedOutput()\n  if err != nil {\n    return fmt.Errorf(\"preflight download failed: %s\", out)\n  }\n  return nil\n}","typeGuard":"null","tryCatchPattern":"// At the call site that drives module collection (e.g. hugofs/modules client):\n// err := c.downloadModuleVersion(path, version)\n// if err != nil {\n//   if strings.Contains(err.Error(), \"failed to download module\") {\n//     // surface the embedded JSON error, fall back to a known-good version\n//   }\n//   return err\n// }","preventionTips":["Pin module versions to tags you control or that are proven fetchable.","Set GOPRIVATE/GOPROXY in the build env before invoking Hugo for private modules.","Run `hugo mod tidy` in CI as a pre-step to fail fast on unreachable modules.","Keep the Go toolchain version within the range your Hugo release supports."],"tags":["modules","network","go-toolchain","hugo-module"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}