golang/go · error
file changed between reads
Error message
file changed between reads
What it means
When embedding a small file (1KB or less), the compiler stats the file to get its size, then reads the entire content with io.ReadAll. After reading, it checks that len(data) equals the stat-reported size. If they differ, the file was modified between the stat and read operations, and this error is returned to prevent embedding inconsistent data.
Source
Thrown at src/cmd/compile/internal/staticdata/data.go:142
if err != nil {
return nil, 0, err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
return nil, 0, err
}
if !info.Mode().IsRegular() {
return nil, 0, fmt.Errorf("not a regular file")
}
size := info.Size()
if size <= 1*1024 {
data, err := io.ReadAll(f)
if err != nil {
return nil, 0, err
}
if int64(len(data)) != size {
return nil, 0, fmt.Errorf("file changed between reads")
}
var sym *obj.LSym
if readonly {
sym = StringSym(pos, string(data))
} else {
sym = slicedata(pos, string(data))
}
if len(hashBytes) > 0 {
sum := hash.Sum32(data)
copy(hashBytes, sum[:])
}
return sym, size, nil
}
if size > maxFileSize {
// ggloblsym takes an int32,
// and probably the rest of the toolchain
// can't handle such big symbols either.
// See golang.org/issue/9862.View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure file generation completes before compilation starts — serialize build steps
- Use atomic file writes: write to a temp file, then os.Rename (rename is atomic on most filesystems)
- Add a dependency in your build system so generated files are ready before go build
- Avoid running file generators and the compiler in parallel on the same files
Defensive patterns
Strategy: validation
Validate before calling
// Ensure embedded files are stable by snapshotting them before build
func snapshotEmbedFiles(dir string) error {
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
// Read the file twice and compare — if it changes, fail
data1, err := os.ReadFile(path)
if err != nil {
return err
}
data2, err := os.ReadFile(path)
if err != nil {
return err
}
if !bytes.Equal(data1, data2) {
return fmt.Errorf("file %s is being modified concurrently — stabilize before build", path)
}
}
return nil
})
} Prevention
- Use atomic file writes (write to temp, then os.Rename) in all file generators
- Serialize build steps so generated files are complete before go build runs
- In Makefiles, add proper dependencies between generation and compilation targets
- Avoid running code generators and the compiler in parallel on the same files
When it happens
Trigger: The embedded file is concurrently modified by another process between the stat() syscall and the read() syscall during compilation. The window is very small (sub-millisecond) so this requires active concurrent writes.
Common situations: Build systems that generate files concurrently with compilation (make -j with overlapping targets). File watchers or linters that rewrite files. Code generators that haven't finished writing when the compiler starts. Network filesystems with eventual consistency.
Related errors
- not a regular file
- file too large (%d bytes > %d bytes)
- invalid quoted string in //go:embed: %s
- go:embed requires go1.16 or later (-lang was set to %s; chec
- error opening profile: %w
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/327df37ab910f9ae.
Report an issue: GitHub.