`go install` issues with custom module: “module … found but does not contain package” & replace-directive error

I have programmed in Go before, but I have never created a Go module myself.

Now I am trying to build a module from scratch, but I am running into issues when I try to install it elsewhere.

I have a project gitlab.com/pipeline-components/org/pipeline-components-linter which lives at pipeline-components / org / Pipeline Components Linter · GitLab. The end-goal is to have an executable called plc-lint

The project follows the Standard Go Project Layout.

  • cmd/ contains the main application
  • internal/ contains private application and library code

The main package is located at cmd/plc-lint/plc-lint.go and has:

package main

The go.mod file has this as module definition:

module gitlab.com/pipeline-components/org/pipeline-components-linter

When I call

go install gitlab.com/pipeline-components/org/pipeline-components-linter@latest

I get the error:

go: gitlab.com/pipeline-components/org/pipeline-components-linter@latest: module gitlab.com/pipeline-components/org/pipeline-components-linter@latest found (v0.9.0), but does not contain package gitlab.com/pipeline-components/org/pipeline-components-linter

I think this is because the main package is not found.

So, instead, I call:

go install gitlab.com/pipeline-components/org/pipeline-components-linter/cmd/plc-lint@latest

I get a different error:

go: gitlab.com/pipeline-components/org/pipeline-components-linter/cmd/plc-lint@latest (in gitlab.com/pipeline-components/org/pipeline-components-linter@v0.9.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.

I think this is better? It definitely has to do with the internal packages and the replace directive in the go.mod.

But now do I have to remove all replace directives to get hings to work?
I don’t know how to do that (i.e. what to replace the replace with).

This is where my (limited) knowledge of Go modules and packages stops

Any explanation about how this works and what do next would be much appreciated.

The problem seems to stem from a misunderstanding on how to use/import internal packages.

The codebase has a go.mod in each internal directory, which it shouldn’t.

Not sure why each internal directory contains its own go.mod. I think my IDE was insisting on it.

Anyway, this causes all internal code to be treated as a module (which I don’t want) instead of as a package (which I do want). The replace was used to patch things together.

The solution is to remove all internal go.mod files and, instead of using replace, using fully qualified import paths:

// INCORRECT
import "internal/asserts"

// CORRECT:
import "gitlab.com/pipeline-components/org/pipeline-components-linter/internal/asserts"

After removing all other go.mod files, removing the replace in the main mod file, and running go mod tidy, everything works as expected.