restic/restic · error
invalid filename specified
Error message
invalid filename specified
What it means
NewReader builds a virtual FS that exposes exactly one file at the given name. The name is cleaned first; if it cleans to "/" there is no filename component to place the reader at, so the constructor rejects it with "invalid filename specified".
Source
Thrown at internal/fs/fs_reader.go:49
fi *ExtendedFileInfo
rc io.ReadCloser
allowEmptyFile bool
children []string
}
// statically ensure that Local implements FS.
var _ FS = &reader{}
// NewReader returns a new FS which provides a directory with a single file. When
// this file is opened for reading, the reader is passed through. The file can
// be opened once, all subsequent open calls return syscall.EIO. For Lstat(),
// the provided FileInfo is returned.
func NewReader(name string, r io.ReadCloser, opts ReaderOptions) (FS, error) {
items := make(map[string]readerItem)
name = readerCleanPath(name)
if name == "/" {
return nil, fmt.Errorf("invalid filename specified")
}
isFile := true
for {
if isFile {
fi := &ExtendedFileInfo{
Name: path.Base(name),
Mode: opts.Mode,
ModTime: opts.ModTime,
Size: opts.Size,
}
items[name] = readerItem{
open: &sync.Once{},
fi: fi,
rc: r,
allowEmptyFile: opts.AllowEmptyFile,
}
isFile = falseView on GitHub (pinned to a80be1478a)
Solutions
- Pass a concrete filename such as "stdin" (restic's own convention is /stdin)
- Guard upstream code that computes the name so it never reduces to the root
Example fix
// before
fs, err := fs.NewReader(filepath.Clean(userPath), r, opts) // userPath == "/"
// after
name := path.Clean(userPath)
if name == "/" || name == "" {
name = "stdin"
}
fs, err := fs.NewReader(name, r, opts) Defensive patterns
Strategy: validation
Validate before calling
name = path.Clean(name)
if name == "/" || name == "" {
return errors.New("reader filename must not be the filesystem root")
} Prevention
- Default reader filenames to a constant like "stdin" instead of ""
- Unit-test the name derivation whenever it comes from user input
- Remember NewReader exposes exactly one file; root-level virtual dirs are not supported
When it happens
Trigger: Calling NewReader("/", r, opts) or with a name that readerCleanPath reduces to the root (empty string, "/", "//").
Common situations: Defaulting a filename variable to "/" or "" when the caller meant something like "stdin"; path-joining bugs that strip the last component.
Related errors
- no command was specified as argument
- unknown grouping option: %q
- failed to parse value %q for feature flag %v: %w
- openfile for readdirnames failed: %w
- readdirnames %v failed: %w
AI-assisted analysis of restic/restic@a80be1478a (2026-08-15).
Data as JSON: /api/errors/2f4a265112fbbfb3.
Report an issue: GitHub.