diff --git a/AGENTS.md b/AGENTS.md
index 22febd9db3c..8bc6860c642 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -8,6 +8,7 @@
* Avoid global state at (almost) all cost.
* This is a project with a long history; assume that a similiar problem has been solved before, look hard for helper functions before creating new ones.
* In tests, use `qt` matchers (e.g. `b.Assert(err, qt.ErrorMatches, ...)`) instead of raw `if`/`t.Fatal` checks.
+* Brevity is good. This applies to code, comments and commit messages. Don't write a novel.
* Use `./check.sh ./somepackage/...` when iterating.
* Use `./check.sh` when you're done.
diff --git a/hugolib/hugo_modules_test.go b/hugolib/hugo_modules_test.go
index cc0bde639f4..450e4cbce88 100644
--- a/hugolib/hugo_modules_test.go
+++ b/hugolib/hugo_modules_test.go
@@ -267,6 +267,29 @@ Home: {{ .Title }}|{{ .Content }}|
b.AssertFileContent("public/index.html", "Home: |
Hello World
\n|")
}
+// https://github.com/gohugoio/hugo/issues/14543
+func TestModulePrivateRepo(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- hugo.toml --
+baseURL = "https://example.com/"
+[module]
+[[module.imports]]
+path = "github.com/bep/this-is-a-non-existing-repo"
+version = "main"
+[[module.imports.mounts]]
+source = "content"
+target = "content"
+-- layouts/all.html --
+Title: {{ .Title }}|
+List: {{ .Title }}
+`
+
+ b, err := TestE(t, files, TestOptOsFs())
+ b.Assert(err, qt.ErrorMatches, `(?s).*mod download.*invalid version.*repository.*`)
+}
+
// https://github.com/gohugoio/hugo/issues/6299
func TestSiteWithGoModButNoModules(t *testing.T) {
t.Parallel()
diff --git a/modules/client.go b/modules/client.go
index dbad4d35cb8..968d1050014 100644
--- a/modules/client.go
+++ b/modules/client.go
@@ -458,6 +458,11 @@ func (c *Client) downloadModuleVersion(path, version string) (*goModule, error)
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)
}
@@ -965,6 +970,18 @@ type goModuleError struct {
Err string // the error itself
}
+func extractGoModDownloadError(b []byte) string {
+ // go mod download -json outputs Error as a plain string,
+ // unlike go list -m -json which uses {"Err": "..."}.
+ var m struct {
+ Error string
+ }
+ if err := json.Unmarshal(b, &m); err == nil && m.Error != "" {
+ return m.Error
+ }
+ return ""
+}
+
type goModules []*goModule
type modSum struct {