Question
How can I check whether a file exists in Go using the standard library, similar to Python's os.path.exists?
Is there an idiomatic Go approach for checking whether a file exists or does not exist?
For example, the goal is to determine whether a path points to an existing file before performing an operation on it.
Short Answer
By the end of this page, you will understand the idiomatic Go way to check whether a file or path exists. You will learn how to use os.Stat, how to detect a missing file with errors.Is(err, os.ErrNotExist), why Go often prefers trying the operation directly, and how to avoid common mistakes when handling file-related errors.
Concept
In Go, checking whether a file exists is usually done by asking the operating system for information about a path.
The most common function for this is:
info, err := os.Stat(path)
This function tries to retrieve file metadata such as size, permissions, and modification time.
- If
err == nil, the path exists. - If
errindicatesos.ErrNotExist, the path does not exist. - If
erris something else, the path might exist, but Go could not access it for another reason, such as permission issues.
A common beginner idea is to want a simple boolean function like exists(path). While you can write one yourself, Go's standard library usually returns both a result and an error so you can tell why something failed.
That matters because these cases are different:
- the file truly does not exist
- the file exists but you do not have permission to read it
- the path is invalid
- the disk or filesystem has another problem
Go code is considered idiomatic when it handles these cases explicitly instead of collapsing everything into true or false.
Another important idea: in real Go programs, developers often avoid checking existence first unless they truly need that information. Instead, they try the operation directly and handle the error. This avoids a time-of-check to time-of-use problem, where a file could be deleted or changed between the check and the actual operation.
Mental Model
Think of os.Stat like asking a building receptionist, "Does room 204 exist, and can you tell me about it?"
Possible answers:
- "Yes, here are the details." → the file exists
- "That room does not exist." → the file does not exist
- "I cannot tell you because you are not allowed access." → permission error
- "Something else went wrong." → another filesystem error
So in Go, you do not just ask "yes or no?" You ask for information, and then inspect the response carefully.
Syntax and Examples
The basic pattern is:
info, err := os.Stat("example.txt")
if err == nil {
fmt.Println("Path exists")
_ = info
} else if errors.Is(err, os.ErrNotExist) {
fmt.Println("Path does not exist")
} else {
fmt.Println("Other error:", err)
}
You need these imports:
import (
"errors"
"fmt"
"os"
)
Example: check whether a path exists
package main
import (
"errors"
"fmt"
"os"
)
func main() {
path := "data.txt"
_, err := os.Stat(path)
if err == nil {
fmt.Println("The path exists")
return
}
if errors.Is(err, os.ErrNotExist) {
fmt.Println("The path does not exist")
return
}
fmt.Println("Could not check path:", err)
}
Example: helper function
Step by Step Execution
Consider this example:
package main
import (
"errors"
"fmt"
"os"
)
func main() {
path := "report.txt"
_, err := os.Stat(path)
if err == nil {
fmt.Println("File exists")
} else if errors.Is(err, os.ErrNotExist) {
fmt.Println("File does not exist")
} else {
fmt.Println("Other error:", err)
}
}
Step by step:
-
path := "report.txt"- A string variable stores the path we want to check.
-
_, err := os.Stat(path)- Go asks the operating system for file information.
_ignores the returned file info because this example only cares whether the path exists.errstores any problem that occurred.
-
if err == nil- If there was no error, Go successfully found the path.
Real World Use Cases
Checking path existence appears in many practical programs:
-
Configuration loading
- Before loading
config.json, a program may check whether the file is present.
- Before loading
-
Log file setup
- A service may check whether a log directory exists before writing files.
-
Import/export tools
- A script may verify that an input CSV file exists before parsing it.
-
CLI utilities
- A command-line tool may warn the user if a specified path is missing.
-
Safe file creation
- An app may avoid overwriting an existing file unless the user passes a
--forceflag.
- An app may avoid overwriting an existing file unless the user passes a
-
Deployment scripts
- Automation code may check for environment files, certificate files, or generated artifacts.
That said, many of these tasks are even better solved by attempting the real operation and handling the error directly.
Real Codebase Usage
In real Go codebases, existence checks are usually used in a few common patterns.
Guard clauses
A program may stop early if a required file is missing:
_, err := os.Stat(configPath)
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("config file not found: %s", configPath)
}
if err != nil {
return fmt.Errorf("could not access config file: %w", err)
}
Validation before processing
Code may validate user input paths before doing expensive work:
func validateInput(path string) error {
_, err := os.Stat(path)
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("input file does not exist")
}
return err
}
Prefer the operation itself
Often developers skip an existence check and just try to open the file:
f, err := os.Open(path)
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("file not found: %s", path)
}
if err != nil {
return err
}
f.Close()
Common Mistakes
1. Treating every error as "file does not exist"
Broken:
_, err := os.Stat(path)
if err != nil {
fmt.Println("File does not exist")
}
Why it is wrong:
err != nilcould mean permission denied, not found, or another error.
Better:
_, err := os.Stat(path)
if err == nil {
fmt.Println("Exists")
} else if errors.Is(err, os.ErrNotExist) {
fmt.Println("Does not exist")
} else {
fmt.Println("Other error:", err)
}
2. Checking first, then assuming the result stays true
Broken idea:
if fileExists(path) {
f, _ := os.Open(path)
// assume this will always work
}
Why it is wrong:
- The file may be deleted or changed between the check and the open.
Better:
f, err := os.Open(path)
if err != nil {
return err
}
f.Close()
Comparisons
| Approach | What it does | Good for | Limitation |
|---|---|---|---|
os.Stat(path) | Gets file info and follows symlinks | General existence checks | Must inspect errors carefully |
os.Lstat(path) | Gets info about the path itself, including symlinks | Working with symlinks | Different behavior from Stat |
os.Open(path) | Tries to open the file directly | Real work like reading files | Not just a check; actually opens the file |
errors.Is(err, os.ErrNotExist) | Checks whether an error means "not found" | Idiomatic error handling | Only useful after an operation returns an error |
Cheat Sheet
info, err := os.Stat(path)
Results
err == nil→ path existserrors.Is(err, os.ErrNotExist)→ path does not exist- other
err→ another problem occurred
Basic pattern
_, err := os.Stat(path)
if err == nil {
// exists
} else if errors.Is(err, os.ErrNotExist) {
// does not exist
} else {
// other error
}
Imports
import (
"errors"
"os"
)
Prefer direct operation when possible
f, err := os.Open(path)
if errors.Is(err, os.ErrNotExist) {
// missing file
}
Symlink note
os.Statfollows symlinksos.Lstatchecks the symlink itself
FAQ
Is there a built-in exists() function in Go?
No. Go usually expects you to use os.Stat or try the real operation directly and inspect the returned error.
What is the idiomatic way to check if a file exists in Go?
Use os.Stat(path) and then check whether the error is os.ErrNotExist with errors.Is(err, os.ErrNotExist).
Should I use os.Stat or os.Open?
If you only need to know whether the path exists, os.Stat is fine. If your real goal is to read the file, prefer os.Open and handle the error directly.
How do I check if a file does not exist in Go?
Use:
if errors.Is(err, os.ErrNotExist) {
// file does not exist
}
Does os.Stat work for directories too?
Yes. os.Stat checks whether the path exists, whether it is a file, directory, or another filesystem entry.
What if I get a permission error?
That does not mean the file is missing. It means Go could not access it. Handle it separately from .
Mini Project
Description
Build a small Go program that checks whether a user-provided path exists and reports whether it is a file, a directory, or missing. This demonstrates idiomatic path checking, error handling, and basic file metadata usage.
Goal
Create a command-line tool that accepts a path and prints a clear result about its existence and type.
Requirements
- Read a path from the command-line arguments.
- Use the Go standard library to inspect the path.
- Print whether the path exists, does not exist, or could not be accessed.
- If the path exists, print whether it is a file or a directory.
Keep learning
Related questions
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.
Convert String to Integer in Go: Idiomatic Parsing with strconv.Atoi
Learn the idiomatic way to convert a string to an int in Go using strconv.Atoi, with examples, errors, and common mistakes.