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

  1. Build ExtendedFileInfo only from os.Stat/os.Lstat results on the matching GOOS
  2. When wrapping os.FileInfo, forward the original Sys() value unchanged
  3. Handle the (bool, error) pair: on error, treat the file as locally available instead of failing the walk
  4. 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

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.