Gotchas with pointing Go modules to a fork, when building an installable module

Featured image for sharing metadata for article

This morning I cut a release of dependency-management-data which ended up horribly breaking all consumers of the application.

As I flagged in the tracking issue for this, trying to install the CLI would lead to the following error:

$ go install dmd.tanna.dev/cmd/dmd@latest
go: dmd.tanna.dev/cmd/dmd@latest (in dmd.tanna.dev@v0.42.0):
	The go.mod file for the module providing named packages contains one or
	more replace directives. It must not contain directives that would cause
	it to be interpreted differently than if it were the main module.

This was because as part of this release, I added support for using charmbracelet/log as a log/slog handler, which isn't yet fully merged upstream so I ended up pointing to my fork of the repo based on this PR.

As mentioned in Pointing to a fork of a Go module this should be trivial to do when you're using a replace directive in your go.mod, and was working in dependency-management-data's build pipeline, up until the point that someone tried to install from it.

I've never had this issue before - despite using replace statements in some projects, and through looking at this Go issue it appears that this is only the case when you have an installable Go module, not when you're building it from the directory that contains the go.mod.

For instance, I have created a sample project on GitLab.com, where we have two modules:

The with-replace module's go.mod:

module gitlab.com/tanna.dev/jvt.me-examples/go-mod-fork-gotcha/with-replace

go 1.21.1

require github.com/charmbracelet/log v0.2.4

// indirects omitted for brevity

replace github.com/charmbracelet/log => github.com/jamietanna/log v0.2.2-0.20230912205513-bfd7186f150d

The without-replace module's go.mod:

module gitlab.com/tanna.dev/jvt.me-examples/go-mod-fork-gotcha/without-replace

go 1.21.1

require github.com/jamietanna/log v0.2.2-0.20230920083807-7382cd7fbdd8

// indirects omitted for brevity

When we try and go install the module that uses replaces, we encounter the same error:

% go install gitlab.com/tanna.dev/jvt.me-examples/go-mod-fork-gotcha/with-replace@HEAD

go: downloading gitlab.com/tanna.dev/jvt.me-examples/go-mod-fork-gotcha v0.0.0-20230920133000-0be73c155bc2
go: downloading gitlab.com/tanna.dev/jvt.me-examples/go-mod-fork-gotcha/with-replace v0.0.0-20230920133000-0be73c155bc2
go: gitlab.com/tanna.dev/jvt.me-examples/go-mod-fork-gotcha/with-replace@HEAD (in gitlab.com/tanna.dev/jvt.me-examples/go-mod-fork-gotcha/with-replace@v0.0.0-20230920133000-0be73c155bc2):
        The go.mod file for the module providing named packages contains one or
        more replace directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.

But when there's not a replace, and we're pinning to a fork, this works as-is.

Also note that the two projects are pinning to a slightly different set of commits - without-replace requires we pin to this specific commit, which modifies the module declaration:

-module github.com/charmbracelet/log
+module github.com/jamietanna/log

go 1.21

Without this, we would receive the error:

go: github.com/jamietanna/log@bfd7186f150d (v0.2.2-0.20230912205513-bfd7186f150d) requires github.com/jamietanna/log@v0.2.2-0.20230912205513-bfd7186f150d: parsing go.mod:
        module declares its path as: github.com/charmbracelet/log
                but was required as: github.com/jamietanna/log

And as we can't specify the replace semantics, we must update the module directive in our go.mod, if we want the module to be installable without someone cloning the repository and running go install from there.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #go.

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.