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

  1. Check first with 'restic -r ... cat config >/dev/null' or 'snapshots' and only init when the repo is absent.
  2. To start fresh, remove or rename the remote directory (or at least its 'config' file) before init.
  3. 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

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


AI-assisted analysis of restic/restic@a80be1478a (2026-08-15). Data as JSON: /api/errors/652527ca52e6574b. Report an issue: GitHub.