golang/go · error

cannot embed %s %s: in non-directory %s

Error message

cannot embed %s %s: in non-directory %s

What it means

In the same ancestor walk (line 2210), for each non-leaf ancestor directory the loader Lstat's it; if it exists but is NOT a directory (a regular file or irregular file sitting where a path component is expected), embedding is impossible. The offending intermediate component is reported relative to pkgdir.

Source

Thrown at src/cmd/go/internal/load/pkg.go:2211

			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:
				return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel)

			case info.Mode().IsRegular():
				if have[rel] != pid {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Rename or remove the file that is occupying a path component that should be a directory.
  2. Correct the //go:embed pattern to point at the real directory.
  3. Ensure any intermediate symlinks resolve to directories (and remember go:embed forbids symlinked directories entirely).

Example fix

// before: pkg/data is a file, //go:embed data/*
// after: rename the file to data.txt and use
//go:embed data_dir/*
Defensive patterns

Strategy: validation

Validate before calling

// Confirm every intermediate path component of an embed target is a directory.
package embedcheck

import (
	"errors"
	"os"
	"path/filepath"
	"strings"
)

func AllAncestorsAreDirs(pkgDir, rel string) error {
	parts := strings.Split(filepath.ToSlash(rel), "/")
	cur := pkgDir
	for i := 0; i < len(parts)-1; i++ {
		cur = filepath.Join(cur, parts[i])
		info, err := os.Lstat(cur)
		if err == nil && !info.IsDir() {
			return errors.New("path component " + cur + " is not a directory")
		}
	}
	return nil
}

Prevention

When it happens

Trigger: An embed glob like `data/*.txt` matches `data/x` where `data` is actually a file, not a directory; or a glob like `a/b/c` where `a/b` is a file. The glob matched because fsys.Glob is permissive but the path is structurally invalid for embedding.

Common situations: A leftover file with the same name as an expected directory; a symlink chain where an intermediate node is a file; case-sensitivity mismatches between a case-insensitive dev box and Linux CI producing phantom matches.

Related errors


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