Introduction
Go's embed package embeds static files into the binary at compile time. Files are embedded relative to the source file containing the //go:embed directive, not the working directory. When paths use backslashes (Windows), include leading slashes, or reference files outside the module, the embed directive silently embeds nothing and fs.ReadFile() returns file does not exist at runtime. The most common cause is path confusion between the Go source file location and the embedded file location.
Symptoms
open templates/index.html: file does not exist
File "embed" does not contain the expected fileOr:
go:embed pattern starts with ..: no matching files foundCommon Causes
- Path relative to wrong directory: Path relative to source file, not CWD
- Backslash on Windows: `
not recognized -- must use/` - Leading slash in path:
/templates/index.htmlfails - Parent directory reference:
../shared/config.yamlnot allowed - Pattern does not match any files: Typo in filename or glob pattern
- Embed directive not on variable declaration: Directive must immediately precede var
Step-by-Step Fix
Step 1: Use correct embed paths
```go package main
import "embed"
// CORRECT: Path relative to this source file, forward slashes // //go:embed templates/index.html var indexTemplate string
// Directory embed // //go:embed all:templates var templateFS embed.FS
func main() { // Access file - path matches embed path exactly data, err := templateFS.ReadFile("templates/index.html") if err != nil { log.Fatal(err) } } ```
Step 2: Handle cross-platform paths
```go package main
import ( "embed" "io/fs" "path" // NOT path/filepath -- always use forward slashes with embed.FS )
//go:embed all:assets var assetsFS embed.FS
func getAsset(name string) ([]byte, error) { // Use path.Join for forward slashes fullPath := path.Join("assets", name) return assetsFS.ReadFile(fullPath) }
func listAssets() error { // Walk embedded filesystem return fs.WalkDir(assetsFS, "assets", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if !d.IsDir() { log.Printf("Embedded file: %s (%d bytes)", path, d.Type()) } return nil }) } ```
Step 3: Debug embedded files
```go func debugEmbeddedFS() { // List all embedded files entries, err := fs.ReadDir(templateFS, ".") if err != nil { log.Printf("Error reading embedded FS: %v", err) return }
log.Printf("Embedded files:") for _, entry := range entries { info, _ := entry.Info() log.Printf(" %s (%d bytes)", entry.Name(), info.Size()) } }
// Build verification: // go build -v ./... # After build, verify files are embedded: go tool nm myapp | grep template # Should show embedded data in binary ```
Prevention
- Always use forward slashes in
//go:embedpaths regardless of OS - Paths are relative to the source file, not the current working directory
- Use
all:directory/to embed directories recursively - Never use
..in embed paths -- Go does not allow parent directory references - Verify embedded files exist at compile time with
go build - Use
fs.ReadDirto list embedded contents at runtime for debugging - Add an integration test that verifies all expected embedded files are accessible