golang/go · error · PackageError

import cycle not allowed in test

Error message

import cycle not allowed in test

What it means

External test packages (foo_test) may import the package under test and its dependencies; the test loader synthesizes a combined graph. A BFS from the test package detects when the synthesized test variant participates in an import loop and records the demonstrated cycle (e.g. p -> q -> r -> p).

Source

Thrown at src/cmd/go/internal/load/test.go:570

				}
				stk = append(stk, ImportInfo{
					Pkg: p.ImportPath,
					Pos: extractFirstImport(importer.Internal.Build.ImportPos[p.ImportPath]),
				})
				p = importerOf[p]
			}
			// complete the cycle: we set importer[p] = nil to break the cycle
			// in importerOf, it's an implicit importerOf[p] == pTest. Add it
			// back here since we reached nil in the loop above to demonstrate
			// the cycle as (for example) package p imports package q imports package r
			// imports package p.
			stk = append(stk, ImportInfo{
				Pkg: ptest.ImportPath,
			})
			slices.Reverse(stk)
			return &PackageError{
				ImportStack:   stk,
				Err:           errors.New("import cycle not allowed in test"),
				IsImportCycle: true,
			}
		}
		for _, dep := range p.Internal.Imports {
			if _, ok := importerOf[dep]; !ok {
				importerOf[dep] = p
				q = append(q, dep)
			}
		}
	}

	return nil
}

// isTestFunc tells whether fn has the type of a testing function. arg
// specifies the parameter type we look for: B, F, M or T.
func isTestFunc(fn *ast.FuncDecl, arg string) bool {
	if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Move shared test helpers into an internal non-test package imported by both the package and its tests.
  2. Remove the production dependency that closes the loop.
  3. Use an interface defined in a lower-level package to break the compile-time cycle.
Defensive patterns

Strategy: validation

Validate before calling

// Run `go vet ./...` and `go test -run xxx ./...` (compile only) to surface
// test-only cycles before the full test run. `go list -test -deps ./...`
// exposes the synthesized test import graph for inspection.

Prevention

When it happens

Trigger: The test package p_test imports a package whose dependency graph, when test variants are merged, leads back to p or p_test; importerOf BFS returns a PackageError with IsImportCycle set.

Common situations: Test helpers placed in a package that imports the package under test, while production code was later made to depend on those helpers; an external test package that imports another package's external test helper; cycles only visible once _test variants are included.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/7c2e952b3640e78e. Report an issue: GitHub.