restic/restic · error

config file already exists

Error message

config file already exists

What it means

The REST backend's Create (used by 'restic init') first opens the repository, stats the config file at ConfigFile, and refuses to proceed when it already exists. This protects the existing repository from being overwritten by a second init.

Source

Thrown at internal/backend/rest/rest.go:95

	cerr := resp.Body.Close()

	// return first error
	if err != nil {
		return errors.Errorf("drain: %w", err)
	}
	return cerr
}

// Create creates a new REST on server configured in config.
func Create(ctx context.Context, cfg Config, rt http.RoundTripper, errorLog func(string, ...any)) (*Backend, error) {
	be, err := Open(ctx, cfg, rt, errorLog)
	if err != nil {
		return nil, err
	}

	_, err = be.Stat(ctx, backend.Handle{Type: backend.ConfigFile})
	if err == nil {
		return nil, errors.New("config file already exists")
	}

	url := *cfg.URL
	values := url.Query()
	values.Set("create", "true")
	url.RawQuery = values.Encode()

	resp, err := be.client.Post(url.String(), "binary/octet-stream", strings.NewReader(""))
	if err != nil {
		return nil, err
	}

	if err := drainAndClose(resp); err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, &restError{backend.Handle{}, resp.StatusCode, resp.Status}

View on GitHub (pinned to a80be1478a)

Solutions

  1. Skip init when the repository exists: run 'restic -r ... snapshots' first and only init when it reports a non-existent repo.
  2. If you truly want a fresh repo, remove or move the old one on the server (delete the config file or the whole prefix) before init.
  3. Verify the URL points at the intended, empty path and does not reuse an existing prefix.

Example fix

# before
restic -r rest:http://server:8000/myrepo init
# -> config file already exists

# after
restic -r rest:http://server:8000/myrepo snapshots || restic -r rest:http://server:8000/myrepo init
Defensive patterns

Strategy: validation

Validate before calling

// check existence before init
_, err := resticStatConfig(repoURL) // e.g. `restic -r <repo> cat config` equivalent
if err == nil {
	return errors.New("repository already initialized; skipping init")
}
// safe to init

Try / catch

err := be.Create(ctx, cfg, rt, nil)
if err != nil {
	if strings.Contains(err.Error(), "config file already exists") {
		// treat as idempotent success or surface a clear message
		log.Printf("repository at %s already exists", cfg.URL)
		return nil
	}
	return err
}

Prevention

When it happens

Trigger: Running 'restic -r rest:<url> init' when the REST server already has a 'config' file at the target; re-initializing after a partial earlier init; pointing the URL at an existing repo path/prefix.

Common situations: Scripts that run init unconditionally on every deployment; copying a repository to the server and then running init; wrong URL prefix so the request lands on an existing repository's namespace.

Related errors


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