{"record":{"id":"652527ca52e6574b","repo":"restic/restic","slug":"config-file-already-exists-652527","errorCode":null,"errorMessage":"config file already exists","messagePattern":"config file already exists","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/sftp/sftp.go","lineNumber":288,"sourceCode":"\targs = append(args, \"-s\", \"sftp\")\n\treturn cmd, args, nil\n}\n\n// Create creates an sftp backend as described by the config by running \"ssh\"\n// with the appropriate arguments (or cfg.Command, if set).\nfunc Create(ctx context.Context, cfg Config, errorLog func(string, ...any)) (*SFTP, error) {\n\tsftp, err := startClient(cfg, errorLog)\n\tif err != nil {\n\t\tdebug.Log(\"unable to start program: %v\", err)\n\t\treturn nil, err\n\t}\n\n\tsftp.Modes = util.DefaultModes\n\n\t// test if config file already exists\n\t_, err = sftp.c.Lstat(sftp.Layout.Filename(backend.Handle{Type: backend.ConfigFile}))\n\tif err == nil {\n\t\treturn nil, errors.New(\"config file already exists\")\n\t}\n\n\t// create paths for data and refs\n\tif err = sftp.mkdirAllDataSubdirs(ctx, cfg.Connections); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// repurpose existing connection\n\treturn open(sftp, cfg)\n}\n\nfunc (r *SFTP) Properties() backend.Properties {\n\treturn backend.Properties{\n\t\tConnections:      r.Config.Connections,\n\t\tHasAtomicReplace: r.posixRename,\n\t}\n}\n","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/restic/restic/blob/a80be1478a4c537f8396e0db2b05120aa78f11e0/internal/backend/sftp/sftp.go#L270-L306","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nrestic -r sftp:admin@nas:/srv/restic init\n# -> config file already exists\n\n# after\nrestic -r sftp:admin@nas:/srv/restic snapshots 2>/dev/null || restic -r sftp:admin@nas:/srv/restic init","handlingStrategy":"try-catch","validationCode":"// probe before init: list the config file over sftp\nif _, err := sftpLstat(repoPath + \"/config\"); err == nil {\n\treturn errors.New(\"repository already initialized\")\n}","typeGuard":null,"tryCatchPattern":"be, err := sftp.Create(ctx, cfg, errorLog)\nif err != nil {\n\tif strings.Contains(err.Error(), \"config file already exists\") {\n\t\treturn nil, fmt.Errorf(\"repository at %s already exists; use open instead of init\", cfg.Path)\n\t}\n\treturn nil, err\n}","preventionTips":["Gate init on a config-existence probe in automation.","Keep init and backup roles separate in scripts."],"tags":["sftp","init","data-safety","configuration"],"backgroundTag":null,"analyzedSha":"a80be1478a4c537f8396e0db2b05120aa78f11e0","analyzedAt":"2026-08-15T15:30:29.928Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}