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

bash
open templates/index.html: file does not exist
  File "embed" does not contain the expected file

Or:

bash
go:embed pattern starts with ..: no matching files found

Common 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.html fails
  • Parent directory reference: ../shared/config.yaml not 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:embed paths 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.ReadDir to list embedded contents at runtime for debugging
  • Add an integration test that verifies all expected embedded files are accessible