golang/go · error
cannot embed %s %s: in different module
Error message
cannot embed %s %s: in different module
What it means
Thrown while walking each ancestor directory of an embed match (loop at line 2204). For every directory from the matched file up toward pkgdir, the loader stats <dir>/go.mod; if a go.mod exists, the embed target is inside a different module. go:embed deliberately cannot cross module boundaries because the embedded bytes would not be reproducible from go.mod alone.
Source
Thrown at src/cmd/go/internal/load/pkg.go:2207
var list []string
for _, file := range match {
// relative path to p.Dir which begins without prefix slash
rel := filepath.ToSlash(str.TrimFilePathPrefix(file, pkgdir))
what := "file"
info, err := fsys.Lstat(file)
if err != nil {
return nil, nil, err
}
if info.IsDir() {
what = "directory"
}
// Check that directories along path do not begin a new module
// (do not contain a go.mod).
for dir := file; len(dir) > len(pkgdir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
return nil, nil, fmt.Errorf("cannot embed %s %s: in different module", what, rel)
}
if dir != file {
if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
return nil, nil, fmt.Errorf("cannot embed %s %s: in non-directory %s", what, rel, dir[len(pkgdir)+1:])
}
}
dirOK[dir] = true
if elem := filepath.Base(dir); isBadEmbedName(elem) {
if dir == file {
return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem)
} else {
return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem)
}
}
}
switch {
default:View on GitHub (pinned to b6b368adc5)
Solutions
- Move the files you want to embed out of the nested module directory into the current package's tree so no go.mod sits between them.
- Delete the stray go.mod in the subdirectory if that subdirectory is not meant to be its own module.
- Restructure so the embedded assets live in the same module as the package with the //go:embed directive.
- If you really need the nested module's files, copy them at build time via go:generate rather than //go:embed.
Example fix
// before: //go:embed vendor/foolib/assets (vendor/foolib/go.mod exists) // after: move assets to ./assets in the main module, then //go:embed assets
Defensive patterns
Strategy: validation
Validate before calling
// Ensure no go.mod sits between the package dir and any embed target.
package embedcheck
import (
"errors"
"os"
"path/filepath"
)
func NoNestedModuleBetween(pkgDir, target string) error {
abs, err := filepath.Abs(filepath.Join(pkgDir, target))
if err != nil {
return err
}
for d := abs; len(d) > len(pkgDir)+1; d = filepath.Dir(d) {
if _, err := os.Stat(filepath.Join(d, "go.mod")); err == nil {
return errors.New("embed target crosses module boundary at " + d)
}
}
return nil
} Prevention
- Keep all embedded assets inside the same module as the embedding package.
- Beware git submodules and `replace` directives into local modules — both introduce go.mod files inside your tree.
When it happens
Trigger: Embedding a path that descends into a nested module: e.g. a vendored copy or a git submodule that has its own go.mod, or a workspace member nested under the main module directory. The match was produced by fsys.Glob, then the ancestor walk finds the foreign go.mod.
Common situations: Adding a nested git submodule that ships a go.mod; using a `replace` to a local path that itself is a module and then trying to embed its files from the parent; embedding a directory that contains a checked-out dependency.
Related errors
- invalid pattern syntax
- use of vendored package not allowed
- cannot embed %s %s: in non-directory %s
- cannot embed %s %s: invalid name %s
- cannot embed %s %s: in invalid directory %s
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/1636d66613daa9ba.
Report an issue: GitHub.