wavetermdev/waveterm · error
error getting file: %v
Error message
error getting file: %v
What it means
GetFile loads the WaveFile for read via entry.loadFileForRead inside a read lock. A fs.ErrNotExist is passed through untouched (the normal 'file not found' case), but any other load failure is wrapped as 'error getting file: %v'. This separates genuine absence from real I/O or storage failures.
Source
Thrown at pkg/filestore/blockstore.go:184
fileNames, err := dbGetZoneFileNames(ctx, zoneId)
if err != nil {
return fmt.Errorf("error getting zone files: %v", err)
}
for _, name := range fileNames {
s.DeleteFile(ctx, zoneId, name)
}
return nil
}
// if file doesn't exsit, returns fs.ErrNotExist
func (s *FileStore) Stat(ctx context.Context, zoneId string, name string) (*WaveFile, error) {
return withLockRtn(s, zoneId, name, func(entry *CacheEntry) (*WaveFile, error) {
file, err := entry.loadFileForRead(ctx)
if err != nil {
if err == fs.ErrNotExist {
return nil, err
}
return nil, fmt.Errorf("error getting file: %v", err)
}
return file.DeepCopy(), nil
})
}
func (s *FileStore) ListFiles(ctx context.Context, zoneId string) ([]*WaveFile, error) {
files, err := dbGetZoneFiles(ctx, zoneId)
if err != nil {
return nil, fmt.Errorf("error getting zone files: %v", err)
}
for idx, file := range files {
withLock(s, file.ZoneId, file.Name, func(entry *CacheEntry) error {
if entry.File != nil {
files[idx] = entry.File.DeepCopy()
}
return nil
})
}View on GitHub (pinned to a4447c1563)
Solutions
- First distinguish absence from failure: check errors.Is(err, fs.ErrNotExist) and handle that as 'file missing', not an error path.
- Inspect the wrapped cause (%v) for the real storage error; retry transient DB failures.
- Ensure the store and DB are healthy and open; re-open/reinitialize if closed.
- Check context deadlines/cancellation on the read path and use an adequate timeout.
Example fix
// before
file, err := store.GetFile(ctx, zoneId, name)
if err != nil {
return err
}
// after
file, err := store.GetFile(ctx, zoneId, name)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return createNewFile(ctx, zoneId, name)
}
return fmt.Errorf("get file %s/%s: %w", zoneId, name, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// distinguish absence from failure after the call; pre-check context
if ctx.Err() != nil { return ctx.Err() } Type guard
func isNotExist(err error) bool { return errors.Is(err, fs.ErrNotExist) } Try / catch
file, err := store.GetFile(ctx, zoneId, name)
if err != nil {
if isNotExist(err) {
// benign: file does not exist
return nil
}
if strings.Contains(err.Error(), "error getting file:") {
// storage failure: retry or surface
return fmt.Errorf("get %s/%s: %w", zoneId, name, err)
}
return err
} Prevention
- Always check errors.Is(err, fs.ErrNotExist) before treating the error as fatal.
- Pass contexts with adequate deadlines for storage reads.
- Keep the backing DB healthy; monitor wrapped causes.
- Handle missing files with a create-or-fallback path instead of failing.
When it happens
Trigger: entry.loadFileForRead returns a non-ErrNotExist error: the backing DB read of file metadata fails, a cache/state inconsistency occurs while materializing the file, the context is cancelled mid-load, or the stored record is corrupt.
Common situations: Underlying store closed or failing while a file is opened; context timeouts on slow storage; a file record partially deleted or corrupted so metadata loads fail; concurrent operations leaving cache entries inconsistent.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- error appending to blockfile: %w
- error truncating blockfile: %w
- error deleting file: %v
- error getting zone files: %v
- error flushing cache entry[%v]: %v
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/79d3d4f2a50fad96.
Report an issue: GitHub.