restic/restic · error
could not determine file attributes: %s
Error message
could not determine file attributes: %s
What it means
On macOS, ExtendedFileInfo.RecallOnDataAccess reports whether a file is dataless (evicted to iCloud Drive, flag SF_DATALESS in Stat_t.Flags). ExtendedFileInfo is built by fs.ExtendedStat from an os.FileInfo, and this method type-asserts the stored Sys() value to *syscall.Stat_t; when the underlying FileInfo came from a different source, the assertion fails and the error names the file.
Source
Thrown at internal/fs/stat_darwin.go:47
Blocks: s.Blocks,
Size: s.Size,
AccessTime: time.Unix(s.Atimespec.Unix()),
ModTime: time.Unix(s.Mtimespec.Unix()),
ChangeTime: time.Unix(s.Ctimespec.Unix()),
sys: s,
}
}
// RecallOnDataAccess checks if a file is available locally on the disk or if the file is
// just a dataless files which must be downloaded from a remote server. This is typically used
// in cloud syncing services (e.g. iCloud drive) to prevent downloading files from cloud storage
// until they are accessed.
func (fi *ExtendedFileInfo) RecallOnDataAccess() (bool, error) {
extAttribute, ok := fi.sys.(*syscall.Stat_t)
if !ok {
return false, fmt.Errorf("could not determine file attributes: %s", fi.Name)
}
const mask uint32 = unix.SF_DATALESS // 0x40000000
if extAttribute.Flags&mask == mask {
return true, nil
}
return false, nil
}
View on GitHub (pinned to a80be1478a)
Solutions
- Build ExtendedFileInfo only from os.Stat/os.Lstat results on the matching GOOS
- When wrapping os.FileInfo, forward the original Sys() value unchanged
- Handle the (bool, error) pair: on error, treat the file as locally available instead of failing the walk
- Gate cloud-eviction checks behind runtime.GOOS == "darwin"
Example fix
// before
fi := myWrappedFileInfo{...} // Sys() returns nil
efi := fs.ExtendedStat(fi)
recall, err := efi.RecallOnDataAccess() // always errors
// after: only inspect files backed by the real darwin stat
if _, ok := fi.Sys().(*syscall.Stat_t); !ok {
recall = false // cannot know; do not force a download
} else {
recall, err = fs.ExtendedStat(fi).RecallOnDataAccess()
} Defensive patterns
Strategy: type-guard
Validate before calling
// ensure the FileInfo originates from the real darwin filesystem layer
if _, ok := fi.Sys().(*syscall.Stat_t); !ok {
recall = false // cannot inspect dataless state on a wrapped FileInfo
} Type guard
func hasDarwinStatT(fi os.FileInfo) bool {
_, ok := fi.Sys().(*syscall.Stat_t)
return ok
} Try / catch
recall, err := efi.RecallOnDataAccess()
if err != nil {
// missing platform stat data: treat as locally available
recall = false
} Prevention
- Forward Sys() unchanged when wrapping os.FileInfo
- Derive ExtendedFileInfo only from os.Stat/os.Lstat on the target GOOS
- Always check the (bool, error) pair instead of assuming success
- Gate platform-specific checks behind runtime.GOOS
When it happens
Trigger: Constructing ExtendedFileInfo from a custom or wrapped os.FileInfo whose Sys() is nil or another type (test fakes, in-memory filesystems, archive walkers); running darwin-specific logic against FileInfo produced by another platform's stat path; restorer code passing archived metadata instead of live stat results.
Common situations: Unit tests with mock filesystems; embedding restic's fs package behind a virtual FS; cross-platform code that forgot a runtime.GOOS gate before calling the darwin-only method.
Related errors
AI-assisted analysis of restic/restic@a80be1478a (2026-08-15).
Data as JSON: /api/errors/1abd807dc4bc76bb.
Report an issue: GitHub.