restic/restic · error
config file already exists
Error message
config file already exists
What it means
The SFTP backend's Create (restic init) starts the client, then Lstats the config file at Layout.Filename(ConfigFile); if it exists, init aborts to prevent clobbering an existing repository, mirroring the guard the local and REST backends have.
Source
Thrown at internal/backend/sftp/sftp.go:288
args = append(args, "-s", "sftp")
return cmd, args, nil
}
// Create creates an sftp backend as described by the config by running "ssh"
// with the appropriate arguments (or cfg.Command, if set).
func Create(ctx context.Context, cfg Config, errorLog func(string, ...any)) (*SFTP, error) {
sftp, err := startClient(cfg, errorLog)
if err != nil {
debug.Log("unable to start program: %v", err)
return nil, err
}
sftp.Modes = util.DefaultModes
// test if config file already exists
_, err = sftp.c.Lstat(sftp.Layout.Filename(backend.Handle{Type: backend.ConfigFile}))
if err == nil {
return nil, errors.New("config file already exists")
}
// create paths for data and refs
if err = sftp.mkdirAllDataSubdirs(ctx, cfg.Connections); err != nil {
return nil, err
}
// repurpose existing connection
return open(sftp, cfg)
}
func (r *SFTP) Properties() backend.Properties {
return backend.Properties{
Connections: r.Config.Connections,
HasAtomicReplace: r.posixRename,
}
}
View on GitHub (pinned to a80be1478a)
Solutions
- Check first with 'restic -r ... cat config >/dev/null' or 'snapshots' and only init when the repo is absent.
- To start fresh, remove or rename the remote directory (or at least its 'config' file) before init.
- Verify the target path is the intended empty directory.
Example fix
# before restic -r sftp:admin@nas:/srv/restic init # -> config file already exists # after restic -r sftp:admin@nas:/srv/restic snapshots 2>/dev/null || restic -r sftp:admin@nas:/srv/restic init
Defensive patterns
Strategy: try-catch
Validate before calling
// probe before init: list the config file over sftp
if _, err := sftpLstat(repoPath + "/config"); err == nil {
return errors.New("repository already initialized")
} Try / catch
be, err := sftp.Create(ctx, cfg, errorLog)
if err != nil {
if strings.Contains(err.Error(), "config file already exists") {
return nil, fmt.Errorf("repository at %s already exists; use open instead of init", cfg.Path)
}
return nil, err
} Prevention
- Gate init on a config-existence probe in automation.
- Keep init and backup roles separate in scripts.
When it happens
Trigger: Running 'restic -r sftp:user@host:/path init' when /path/config already exists on the remote; re-running init after an earlier partial creation; pointing at a directory that already holds a repo.
Common situations: Idempotent deployment scripts that always init; restoring a copied repo directory and then initializing into it; wrong path in automation pointing at the production repo.
Related errors
- config file already exists
- sftp: invalid format, hostname or path not found
- invalid format, does not start with "sftp:"
- sftp path starts with the tilde (~) character, that fails fo
- cannot specify both sftp.command and sftp.args options
AI-assisted analysis of restic/restic@a80be1478a (2026-08-15).
Data as JSON: /api/errors/652527ca52e6574b.
Report an issue: GitHub.