AlexxIT/go2rtc · error

err.Error()

Error message

err.Error()

What it means

In restartHandler, if os.Executable() fails (it cannot determine the path of the running binary), the error text is returned verbatim as a 500 response. This is not a panic message but the propagated err.Error() string.

Solutions

  1. Ensure the go2rtc binary still exists at its original path, then retry POST /api/restart
  2. Restart the container/service via the platform (docker restart, systemctl restart) instead of the API
  3. If running from a deleted file, start go2rtc from a stable path before relying on API restart

Example fix

// before
# binary replaced in place -> inode deleted
curl -X POST http://host:1984/api/restart
// after
docker restart go2rtc   # or systemctl restart go2rtc, then verify binary exists before API restart
Defensive patterns

Strategy: try-catch

Try / catch

const res = await fetch(url, { method: 'POST' });
if (!res.ok) {
  const detail = await res.text();
  throw new Error('restart failed (' + res.status + '): ' + detail);
}

Prevention

When it happens

Trigger: Calling POST /api/restart when the executable path can't be resolved - e.g. the binary was deleted/replaced on disk while running, or running in an environment where /proc-style path resolution fails (deleted inode: 'os.Executable: ... no such file or directory').

Common situations: Container images where the binary was swapped/removed after start; upgraded binary deleted the old inode; unusual embedded environments.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/3a0408e59c8737ba. Report an issue: GitHub.

Appendix: source

Thrown at internal/api/api.go:272

	// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_02
	if err != nil || code < 0 || code > 125 {
		http.Error(w, "Code must be in the range [0, 125]", http.StatusBadRequest)
		return
	}

	os.Exit(code)
}

func restartHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "", http.StatusBadRequest)
		return
	}

	path, err := os.Executable()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	log.Debug().Msgf("[api] restart %s", path)

	go syscall.Exec(path, os.Args, os.Environ())
}

func logHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		// Send current state of the log file immediately
		w.Header().Set("Content-Type", "application/jsonlines")
		_, _ = app.MemoryLog.WriteTo(w)
	case "DELETE":
		app.MemoryLog.Reset()
		Response(w, "OK", "text/plain")
	default:

View on GitHub (pinned to c245815e75)