syncthing/syncthing · info · svcutil.FatalErr

restart after db reset initiated by rest API

Error message

restart after db reset initiated by rest API

What it means

This is not a failure: it is a deliberately constructed sentinel error passed to s.fatal() by the REST handler for POST /rest/system/reset after the handler has flushed a success response. It instructs the supervised process to exit with svcutil.ExitRestart so the supervisor restarts Syncthing and the just-wiped or reset database is reopened cleanly. Any caller of the reset endpoint should expect the process to terminate by design.

Source

Thrown at lib/api/api.go:1016

		// Reset all folders.
		for folder := range s.cfg.Folders() {
			if err := s.model.ResetFolder(folder); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		s.flushResponse(`{"ok": "resetting database"}`, w)
	} else {
		// Reset a specific folder, assuming it's supposed to exist.
		if err := s.model.ResetFolder(folder); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		s.flushResponse(`{"ok": "resetting folder `+folder+`"}`, w)
	}

	s.fatal(&svcutil.FatalErr{
		Err:    errors.New("restart after db reset initiated by rest API"),
		Status: svcutil.ExitRestart,
	})
}

func (s *service) postSystemShutdown(w http.ResponseWriter, _ *http.Request) {
	s.flushResponse(`{"ok": "shutting down"}`, w)
	s.fatal(&svcutil.FatalErr{
		Err:    errors.New("shutdown initiated by rest API"),
		Status: svcutil.ExitSuccess,
	})
}

func (*service) flushResponse(resp string, w http.ResponseWriter) {
	w.Write([]byte(resp + "\n"))
	f := w.(http.Flusher)
	f.Flush()
}

View on GitHub (pinned to 058bcd7334)

Solutions

  1. Treat the flushed '{"ok": "resetting..."}' response as the success signal and stop making further API calls until the service restarts.
  2. Have your supervision wrapper (systemd, docker restart policy, syncthing's own -resume or supervisor) restart the process on the ExitRestart exit status.
  3. If you only wanted to reset one folder, pass ?folder=<id> and still expect the restart, since the handler always calls s.fatal with ExitRestart.
  4. Back up index databases before calling reset if you might need the data; reset is destructive.
Defensive patterns

Strategy: validation

Validate before calling

// Before calling reset, confirm you really want a restart:
// POST /rest/system/reset always ends with the process exiting (ExitRestart).
// Validate preconditions (backup taken, no in-flight transfers) first.
resp, err := http.Post(apiURL+"/rest/system/reset", "", nil)
// After reading '{"ok": "resetting..."}', stop calling the API until restart completes.

Try / catch

// Not applicable: this is a deliberate process-exit sentinel, not a catchable
// API error. The response body '{"ok": "resetting database"}' is the success signal.

Prevention

When it happens

Trigger: POST /rest/system/reset (with or without ?folder=...) reaching the end of the handler: after ResetAll or model.ResetFolder succeeds and '{"ok": "resetting..."}' has been flushed, s.fatal(&svcutil.FatalErr{Err: errors.New("restart after db reset initiated by rest API"), Status: svcutil.ExitRestart}) is invoked unconditionally.

Common situations: Automation or a GUI script calling the reset endpoint and then being surprised that subsequent REST calls fail because the process exited; expecting an error body instead of the flushed ok JSON followed by process exit.

Related errors


AI-assisted analysis of syncthing/syncthing@058bcd7334 (2026-08-15). Data as JSON: /api/errors/6f68ebd58e15c87d. Report an issue: GitHub.