Golang os.Stat: file metadata, FileInfo, and os.ErrNotExist

Golang os.stat and golang os stat: os.Stat returns fs.FileInfo (name, size, mode, mod time, IsDir); *File.Stat; errors.Is(err, os.ErrNotExist); os.Lstat vs Stat; PathError. Related os package file I/O.

Published

Updated

Read time 3 min read

Reviewed byDeepak Prasad

Golang os.Stat: file metadata, FileInfo, and os.ErrNotExist

Searches like golang os.stat, os.stat golang, golang os stat, go os stat, or os stat golang all point at the same API: os.Stat returns metadata about a path without opening it for I/O. The result is an fs.FileInfo (historically documented under os; the interface lives in io/fs today). For open handles, (*os.File).Stat answers the same questions for the file descriptor you already hold. This page is about that metadata path; for general reads and writes, see the broader golang os package article and reading and updating the same file.

Tested with Go 1.24 on Linux.


golang os.Stat and fs.FileInfo

func Stat(name string) (fs.FileInfo, error) stats the named file. On success you get methods such as Name, Size, Mode, ModTime, and IsDir. On failure the error is typically a *fs.PathError (older docs call it *os.PathError; it implements error and unwraps to the underlying cause).

Prefer printing a few fields instead of %+v on the concrete FileInfo implementation, which dumps unexported layout that changes between releases:

go
package main

import (
	"fmt"
	"log"
	"os"
	"time"
)

func main() {
	fi, err := os.Stat("statdemo.txt")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("name=%s size=%d mode=%s mod=%s isDir=%v\n",
		fi.Name(), fi.Size(), fi.Mode(), fi.ModTime().UTC().Format(time.RFC3339), fi.IsDir())
}
text
name=statdemo.txt size=16 mode=-rw-rw-r-- mod=2026-06-17T18:42:45Z isDir=false

Create statdemo.txt in the current directory before running; your size, mode, and timestamp will differ.

(*os.File).Stat after os.Open

If you already opened the path, Stat on the file uses the same descriptor (useful right after Open or Create):

go
package main

import (
	"fmt"
	"log"
	"os"
	"time"
)

func main() {
	f, err := os.Open("statdemo.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("from File.Stat: name=%s size=%d mod=%s\n",
		fi.Name(), fi.Size(), fi.ModTime().UTC().Format(time.RFC3339))
}
text
from File.Stat: name=statdemo.txt size=16 mod=2026-06-17T18:42:45Z

Existence checks with os.stat / os.Stat

The usual os.stat go pattern for “does this path exist?” is to call os.Stat and inspect the error. Use errors.Is with os.ErrNotExist so wrapped errors still work:

go
package main

import (
	"errors"
	"fmt"
	"os"
)

func pathExists(name string) (bool, error) {
	_, err := os.Stat(name)
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return false, nil
		}
		return false, err
	}
	return true, nil
}

func main() {
	for _, p := range []string{"statdemo.txt", "nope.txt"} {
		ok, err := pathExists(p)
		fmt.Println(p, ok, err)
	}
}
text
statdemo.txt true <nil>
nope.txt false <nil>

If you need “exists and is a regular file,” combine Stat with !info.IsDir() (and optionally info.Mode().IsRegular() on platforms where that matters). A directory path still exists: Stat succeeds and IsDir() is true.

os.IsNotExist is still available, but errors.Is(err, os.ErrNotExist) is the idiomatic choice in new code.


os.Lstat is like Stat but does not follow a final symbolic link: you see the link’s own metadata. os.Stat follows links and describes the target. Pick Lstat when symlink identity matters (for example tools that delete or rewrite the link itself).


Summary

Golang os.stat style lookups use os.Stat to obtain an fs.FileInfo without opening the file for reads or writes, or (*os.File).Stat when you already have a handle. For “not found,” rely on errors.Is(err, os.ErrNotExist) rather than string matching on errors. Use os.Lstat when you must not follow symlinks. For printing structs for debugging, see printing structs in Go, but prefer explicit fields for FileInfo in documentation and logs.


References


Frequently Asked Questions

1. What is the difference between os.Stat and os.Lstat in Go?

os.Stat follows symbolic links and describes the target. os.Lstat describes the path itself; if it is a symlink you see the link metadata instead of the target.

2. When should I use os.Stat instead of opening the file?

Use os.Stat when you only need metadata (size, mode, mod time, directory bit) without reading bytes. Open the file when you also need to read, write, or seek, then use (*os.File).Stat for the same descriptor.

3. How do I test for “file not found” from os.Stat?

Compare with errors.Is(err, os.ErrNotExist). os.IsNotExist exists for backward compatibility but errors.Is is the preferred pattern with wrapped errors.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …