Go: cmd/go: 'cannot find module for path' when importing from subdirectories

Created on 27 Jul 2018  ยท  10Comments  ยท  Source: golang/go

What version of Go are you using (go version)?

go version go1.11beta2 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOCACHE="/home/markkuit/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/markkuit/go/"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/tmp/gomodsubdirs/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build236792179=/tmp/go-build -gno-record-gcc-switches"

What did you do?

The issue arises when using modules when having imports from subdirectories. I created a easy to reproduce example:

/tmp/gomodsubdirs/go.mod
module testmodule.local/gomodsubdirs

/tmp/gomodsubdirs/main.go

package main

import (
    "./subdir"
    "fmt"
)

func main() {
    fmt.Println("Printing from main!")
    subdir.Print()
}

/tmp/gomodsubdirs/subdir/subdir.go

package subdir

import "fmt"

func Print() {
    fmt.Println("Printing from subdir!")
}

What did you expect to see?

I expected build to be successful both with and without modules, but it looks like putting code in subdirectories is troublesome for go modules (or I'm doing something wrong). I tend to do this quite a lot when I have a package in a subdirectory with a lot of files (mostly boilerplate code), which isn't however worthy of being a separate package itself or is too strictly related to the main package to be put apart from it. Note that I tried having a go.mod inside the subdirectory as well (both empty and filled), but it made no difference.

What did you see instead?

> go build main.go
build .: cannot find module for path _/tmp/gomodsubdirs/subdir
> env GO111MODULE=off go build main.go
> ./main
Printing from main!
Printing from subdir!
FrozenDueToAge modules

Most helpful comment

Sorry but this is working as intended. This kind of "relative import" was something we had in the very early days of go, before there was a go command, but when we moved to the go command and GOPATH we finally had a way to give a fully-qualified path for imports, at least within GOPATH, and we standardized on that fully-qualified form for tools and such. The relative imports still worked outside GOPATH, essentially out of a combination of necessity and neglect, but they didn't work as well. Among other things, until Go 1.10 there was no build caching, so that builds were slower. Many tools don't handle them right. But they were left in because otherwise there was no name for that subdirectory.

In modules, there finally is a name for the subdirectory. If the parent directory says "module m" then the subdirectory is imported as "m/subdir", no longer "./subdir".

I do apologize that we don't have something that works both ways, but we definitely want to preserve the property for the vast majority of Go code that imports are fully-qualified, and so we don't want moving to modules to lose that property. Instead moving from "outside GOPATH one-off directories" to modules requires using the newly-available fully-qualified name.

Best,
Russ

All 10 comments

Sorry but this is working as intended. This kind of "relative import" was something we had in the very early days of go, before there was a go command, but when we moved to the go command and GOPATH we finally had a way to give a fully-qualified path for imports, at least within GOPATH, and we standardized on that fully-qualified form for tools and such. The relative imports still worked outside GOPATH, essentially out of a combination of necessity and neglect, but they didn't work as well. Among other things, until Go 1.10 there was no build caching, so that builds were slower. Many tools don't handle them right. But they were left in because otherwise there was no name for that subdirectory.

In modules, there finally is a name for the subdirectory. If the parent directory says "module m" then the subdirectory is imported as "m/subdir", no longer "./subdir".

I do apologize that we don't have something that works both ways, but we definitely want to preserve the property for the vast majority of Go code that imports are fully-qualified, and so we don't want moving to modules to lose that property. Instead moving from "outside GOPATH one-off directories" to modules requires using the newly-available fully-qualified name.

Best,
Russ

This actually makes perfect sense, and I do agree it was a choice that had be taken. What I was worried about was not having the possibility to organize code in subdirectories anymore; instead, I can confirm specifying the full import path achieves the goal - even if the module isn't under any VCS yet.

I'll take this opportunity to thank you (and the whole team) for your continued efforts, and thank you for clarifying this issue.

In modules, there finally is a name for the subdirectory. If the parent directory says "module m" then the subdirectory is imported as "m/subdir", no longer "./subdir".

How about sibling packages?
I have a folder structure:

- Root
  |--- mod1
       |--- go.mod
  |--- mod2
       |--- go.mod

I couldn't find a way to import mod2 from mod1.

How about sibling packages?

Never mind, I got the answer in the Go Wiki.

For someone like me, here is the relevant part:
image

Hi @rsc,

In modules, there finally is a name for the subdirectory. If the parent directory says "module m" then the subdirectory is imported as "m/subdir", no longer "./subdir".

Is this something which should work now or is it going to be added?
I can't get this to work with go 1.12:

~/tmp$ tree topdir/
topdir/
โ”œโ”€โ”€ go.mod
โ”œโ”€โ”€ subdir
โ”‚ย ย  โ””โ”€โ”€ subdir.go
โ””โ”€โ”€ topdir.go

1 directory, 3 files
~/tmp$ cat topdir/go.mod 
module example.com/topdir

go 1.12
~/tmp$ cat topdir/topdir.go 
package topdir

import "topdir/subdir"

type Topdir subdir.Subdir
~/tmp$ cat topdir/subdir/subdir.go 
package subdir

type Subdir interface{}
~/tmp$ cd topdir/
~/tmp/topdir$ go build
topdir.go:3:8: unknown import path "topdir/subdir": cannot find module providing package topdir/subdir

@figiel I think there is a subtle difference in your import compared to what is defined in the import definition. In your go.mod the module is named example.com/topdir so m=example.com/topdir. Therefore in your files you should be importing like example.com/topdir/subdir

I have the same problem. When you close the module, it compiles; when you open it, the same error is reported. I open a new terminal window to compile through.

same issue with 1.13 . when to expect patch?

@xtrimf You need go modules. It's actually really easy to set it up: https://blog.golang.org/using-go-modules

@warent tnx. already did two month ago...

Was this page helpful?
0 / 5 - 0 ratings