Understanding File Not Found Errors

File not found errors in Go appear as:

bash
open config.json: no such file or directory
stat /path/to/file: no such file or directory
open /tmp/data.txt: The system cannot find the file specified.

The error type is *os.PathError with Op, Path, and Err fields.

Common Scenarios and Solutions

Scenario 1: Relative Path Confusion

Problem code: ``go func main() { data, err := os.ReadFile("config.json") if err != nil { log.Fatal(err) // open config.json: no such file or directory } }

When you run go run main.go vs ./myapp vs cd cmd && go run main.go, the working directory changes.

Solution - Use absolute paths or embed files: ```go // Option 1: Get executable directory func getExeDir() string { exe, err := os.Executable() if err != nil { log.Fatal(err) } return filepath.Dir(exe) }

func main() { configPath := filepath.Join(getExeDir(), "config.json") data, err := os.ReadFile(configPath) if err != nil { log.Fatal(err) } }

// Option 2: Use embed (Go 1.16+) //go:embed config.json var configData []byte

func main() { var cfg Config json.Unmarshal(configData, &cfg) }

// Option 3: Accept path as argument func main() { if len(os.Args) < 2 { log.Fatal("Usage: myapp <config-file>") } configPath := os.Args[1] data, err := os.ReadFile(configPath) if err != nil { log.Fatal(err) } } ```

Scenario 2: Path Separator Issues (Cross-Platform)

Problem code: ``go func main() { path := "data\\files\\config.json" // Windows-style data, err := os.ReadFile(path) // Works on Windows, fails on Linux/Mac }

Solution - Use filepath package: ```go func main() { path := filepath.Join("data", "files", "config.json") data, err := os.ReadFile(path) if err != nil { log.Fatal(err) } }

// Also use filepath.Clean for user input func main() { userInput := "data/../secrets/password.txt" cleanPath := filepath.Clean(userInput) // "secrets/password.txt" // But validate it's within expected directory! } ```

Scenario 3: Missing Parent Directory

Problem code: ``go func main() { err := os.WriteFile("data/output/result.txt", []byte("hello"), 0644) if err != nil { log.Fatal(err) // open data/output/result.txt: no such file or directory } }

Solution - Create parent directories: ```go func writeFile(path string, data []byte) error { // Create parent directories if needed dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("creating directories: %w", err) }

return os.WriteFile(path, data, 0644) }

func main() { err := writeFile("data/output/result.txt", []byte("hello")) if err != nil { log.Fatal(err) } } ```

Scenario 4: File Exists Check Race Condition

Problem code: ``go func main() { if _, err := os.Stat("file.txt"); os.IsNotExist(err) { // File doesn't exist, create it f, _ := os.Create("file.txt") defer f.Close() } else { // File exists - but another process might have deleted it! f, _ := os.Open("file.txt") // Could fail! defer f.Close() } }

Solution - Just try to open/create: ```go func main() { // Create if not exists, or open if exists f, err := os.OpenFile("file.txt", os.O_RDWR|os.O_CREATE, 0644) if err != nil { log.Fatal(err) } defer f.Close()

// Or use exclusive create f, err := os.OpenFile("file.txt", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644) if os.IsExist(err) { // File already exists f, err = os.Open("file.txt") } if err != nil { log.Fatal(err) } defer f.Close() } ```

Scenario 5: Permission Denied Disguised as Not Found

Error: `` open /root/config.json: no such file or directory

This might actually be a permission issue. Check with:

```go func checkFileAccess(path string) error { // Check if file exists info, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { return fmt.Errorf("file does not exist: %s", path) } if os.IsPermission(err) { return fmt.Errorf("permission denied: %s", path) } return fmt.Errorf("error accessing file: %w", err) }

// Check read permission file, err := os.Open(path) if err != nil { if os.IsPermission(err) { return fmt.Errorf("read permission denied: %s", path) } return err } file.Close()

// Check write permission (if needed) if info.Mode().Perm()&0200 == 0 { return fmt.Errorf("write permission denied: %s", path) }

return nil } ```

Scenario 6: Symlink Issues

Problem code: ``go func main() { // Following a broken symlink data, err := os.ReadFile("link-to-deleted-file") // Error: no such file or directory }

Solution - Check symlink target: ```go func main() { path := "link-to-file"

// Check if it's a symlink info, err := os.Lstat(path) if err != nil { log.Fatal(err) }

if info.Mode()&os.ModeSymlink != 0 { // It's a symlink, get the target target, err := os.Readlink(path) if err != nil { log.Fatal(err) }

// Check if target exists if _, err := os.Stat(target); os.IsNotExist(err) { log.Fatalf("symlink target does not exist: %s", target) } } } ```

Robust File Reading Pattern

```go func readFileRobust(path string) ([]byte, error) { // Clean the path path = filepath.Clean(path)

// Make absolute if relative if !filepath.IsAbs(path) { absPath, err := filepath.Abs(path) if err != nil { return nil, fmt.Errorf("getting absolute path: %w", err) } path = absPath }

// Check if exists info, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { return nil, fmt.Errorf("file not found: %s", path) } if os.IsPermission(err) { return nil, fmt.Errorf("permission denied: %s", path) } return nil, fmt.Errorf("stat error: %w", err) }

// Check it's a regular file if !info.Mode().IsRegular() { return nil, fmt.Errorf("not a regular file: %s", path) }

// Read the file data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading file: %w", err) }

return data, nil } ```

Finding Files in Standard Locations

```go // Find config in standard locations func findConfig(name string) (string, error) { locations := []string{ ".", // Current directory "./config", // Config subdirectory filepath.Join(os.Getenv("HOME"), ".myapp"), // Home directory "/etc/myapp", // System config "/usr/local/etc/myapp", // Local system config }

for _, loc := range locations { path := filepath.Join(loc, name) if _, err := os.Stat(path); err == nil { return path, nil } }

return "", fmt.Errorf("config file %q not found in any standard location", name) }

// Use XDG Base Directory specification on Linux func xdgConfigPath(name string) string { if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" { return filepath.Join(xdg, "myapp", name) } return filepath.Join(os.Getenv("HOME"), ".config", "myapp", name) } ```

Verification

```bash # Check if file exists ls -la /path/to/file

# Check permissions stat /path/to/file

# Check working directory pwd

# Run with debug strace -e openat ./myapp 2>&1 | grep config.json ```