240

I have a problem with

import cycle not allowed

It appears when I am trying to test my controller. Here is the output:

can't load package: import cycle not allowed
package project/controllers/account
    imports project/controllers/base
    imports project/components/mux
    imports project/controllers/account
import cycle not allowed
package project/controllers/account
    imports project/controllers/base
    imports project/components/mux
    imports project/controllers/account
import cycle not allowed
package project/controllers/account
    imports project/controllers/base
    imports project/components/mux
    imports project/controllers/routes
    imports project/controllers/base

How do I read or understand this error? Where is the dependency wrong?

tshepang
  • 12,111
  • 21
  • 91
  • 136
softshipper
  • 32,463
  • 51
  • 192
  • 400
  • 24
    The `account` package imports the `base` package, which imports the `mux` package, which imports the `account` package. That's a cyclical set of import dependencies, which is not allowed. It looks like you have another cycle as well, `base` imports `mux`, which imports `routes`, which imports `base`. – Amit Kumar Gupta Jan 31 '15 at 21:53
  • 9
    it would be better if compiler could print the line numbers to follow the import cycle. One package can have many files. – weima Jul 20 '21 at 14:13

8 Answers8

287

Here is an illustration of your first import cycle problem.

                  project/controllers/account
                     ^                    \    
                    /                      \
                   /                        \ 
                  /                         \/
         project/components/mux <--- project/controllers/base
            
                   

As you can see with my bad ASCII chart, you are creating an import cycle when project/components/mux imports project/controllers/account. Since Go does not support circular dependencies you get the import cycle not allowed error during compile time.

tshepang
  • 12,111
  • 21
  • 91
  • 136
jmaloney
  • 11,580
  • 2
  • 36
  • 29
  • 47
    So bad this shows up on compiling only. Wasted a lot of time for restructuring my hole project just to see I'm not allowed to do what I did... dafug... – C4d Aug 20 '18 at 10:26
  • 35
    Allowing circular deps would significantly increase compile times since your entire circle of deps would need to get recompiled every time one of the deps changed. Having circular deps is also a heavy cognitive load since it makes it harder to reason about your program and tends towards complexity. – jmaloney Oct 02 '18 at 16:01
  • which linter are you using i dont see any linting on vs code – Gopherine Sep 03 '19 at 20:23
  • I can see this error while running app through `watcher` – R Sun Sep 07 '19 at 19:14
  • 2
    This can be resolved by defining a custom interface through which each package can link to types of other packages, instead of importing them directly. – Coconut Sep 22 '20 at 05:27
  • 1
    @Lucas, how can you like technical limitation, that make development harder? – Michael Freidgeim Jul 03 '21 at 23:23
  • 19
    This "answer" explains the problem but does not provide a working solution. – tutiplain Sep 22 '21 at 14:56
  • @tutiplain The question was "How do I read or understand this error? Where is the dependency wrong?" And this answer answers that question. Fixing the problem would involve refactoring the code to not have an import cycle. – jmaloney Sep 22 '21 at 15:20
  • 14
    somehow I never had this problem with java... why am I using Go again? – alex Nov 13 '21 at 17:32
  • Why can't they give each import a key so it only gets included once? – TheRealChx101 May 06 '22 at 21:28
172

I just encountered this. You may be accessing a method/type from within the same package using the package name itself.

Here is an example to illustrate what I mean:

In foo.go:

// foo.go
package foo

func Foo() {...}

In foo_test.go:

// foo_test.go
package foo

// try to access Foo()
foo.Foo() // WRONG <== This was the issue. You are already in package foo, there is no need to use foo.Foo() to access Foo()
Foo() // CORRECT

Another common cause of circular dependency is shown in this answer.

Unlike JavaScript, Go has low tolerance for circular dependencies, which is both a good and a bad thing.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Jonathan Lin
  • 19,922
  • 7
  • 69
  • 65
  • 28
    In my opinion this is the better answer. The accepted answer is just as valid, but doesn't explain anything other than the theory for such a failure. @Jonathan Lin 's answer however, perfectly explains this cryptic error message, and how to combat it. – laminatefish Oct 11 '18 at 14:15
  • 6
    It's 2020 and I propose that this should be the better and accepted answer. @stackoverflow – Louie Miranda Aug 25 '20 at 09:05
  • 5
    This answer only givers one instance of a circular import and it's the least complicated one at that, a package that imports itself. Most of the time when you encounter this error you are many packages removed and understanding how to interpret the error will get you a lot further than understanding one instance of how the error can occur – jmaloney May 06 '21 at 01:15
16

This is a circular dependency issue. Golang programs must be acyclic. In Golang cyclic imports are not allowed (That is its import graph must not contain any loops)

Lets say your project go-circular-dependency have 2 packages "package one" & it has "one.go" & "package two" & it has "two.go" So your project structure is as follows

+--go-circular-dependency    
      +--one    
         +-one.go
      +--two        
         +-two.go

This issue occurs when you try to do something like following.

Step 1 - In one.go you import package two (Following is one.go)

package one

import (
    "go-circular-dependency/two"
)

//AddOne is
func AddOne() int {
    a := two.Multiplier()
    return a + 1
}

Step 2 - In two.go you import package one (Following is two.go)

package two

import (
    "fmt"
    "go-circular-dependency/one"
)

//Multiplier is going to be used in package one
func Multiplier() int {
    return 2
}

//Total is
func Total() {
    //import AddOne from "package one"
    x := one.AddOne()
    fmt.Println(x)
}

In Step 2, you will receive an error "can't load package: import cycle not allowed" (This is called "Circular Dependency" error)

Technically speaking this is bad design decision and you should avoid this as much as possible, but you can "Break Circular Dependencies via implicit interfaces" (I personally don't recommend, and highly discourage this practise, because by design Go programs must be acyclic)

Try to keep your import dependency shallow. When the dependency graph becomes deeper (i.e package x imports y, y imports z, z imports x) then circular dependencies become more likely.

Sometimes code repetition is not bad idea, which is exactly opposite of DRY (don't repeat yourself)

So in Step 2 that is in two.go you should not import package one. Instead in two.go you should actually replicate the functionality of AddOne() written in one.go as follows.

package two

import (
    "fmt"
)

//Multiplier is going to be used in package one
func Multiplier() int {
    return 2
}

//Total is
func Total() {
    // x := one.AddOne()
    x := Multiplier() + 1
    fmt.Println(x)
}
wchargin
  • 15,589
  • 12
  • 71
  • 110
Sachin Raut
  • 328
  • 3
  • 13
  • 4
    thanks for the answer, however I like the DRY methodology due to maintainability. For me saying "Sometimes code repetition is not bad idea" is not nice, because if i have common functionality between 12 struct groups, i have to write it 12 times in each, and update that code 12 times. – ASH Nov 12 '20 at 15:40
  • 1
    Yes. You are right about 12. But if it has only 2 or 3 in different services - sometimes it not so bad. Just like create a table in DB with lower normalization level but avoid additional join to optimize it. – trashgenerator Nov 19 '20 at 15:29
  • “Break Circular Dependencies via implicit interfaces" (I personally don't recommend, and highly discourage this practise, because by design Go programs must be acyclic) . It is Go technical limitation, not the architectural advantage of Go. Using interfaces is a good solution to work around the limitation if developers need it. – Michael Freidgeim Apr 24 '21 at 02:11
5

You may have imported,

project/controllers/base

inside the

project/controllers/routes

You have already imported before. That's not supported.

Thushara Buddhika
  • 1,652
  • 12
  • 14
5

Error The error results from having two modules importing each other simultaneously.

Module A importing Module B
Module B importing Module A

Solution Find a way to make the two way imports a one way import.

bitbuoy
  • 353
  • 2
  • 8
2

I got another solution for this.

My case

  1. I found out that I had not run the command : go mod init <module_name> before starting to work on the project.

  2. Later I was trying to import the "mux" package go get github/gorilla/mux and then I was getting the error "Import cycle not allowed".

Check if you have initialized a module( the command mentioned in pt 1.) if required in the directory that you are working. Then try running the script.

2

Reason for import cycle has been mentioned in above answers. I was facing import cycle issue for built-in lib while running a command go build -mod vendor

Ex:
...
...
imports github.com/aws/aws-sdk-go/aws
    imports net/http
    imports crypto/tls
    imports crypto/ecdsa
    imports crypto/elliptic
    imports crypto/internal/nistec
    imports crypto/elliptic: import cycle not allowed

...
...
    imports fmt
    imports errors
    imports internal/reflectlite
    imports runtime
    imports internal/abi
    imports internal/goarch
    imports bytes
    imports errors: import cycle not allowed

It was solved by uninstalling golang and reinstalling it. I think I didnt install the golang correctly before. Thanks for the hint in https://bytemeta.vip/repo/fyne-io/fyne/issues/3089. I couldnt give credits to that person there but mentioning here. Thanks.

1

Sometimes you give the same module name using command ' go mod init x/y/z' and you have the same import as well. This was very hard to solve at least for me. Just give any meaningful name to your mod e.g, 'go mod init sid'

siddhusingh
  • 1,832
  • 4
  • 25
  • 30