sipeed/picoclaw · error

Failed to restart gateway: %v

Error message

Failed to restart gateway: %v

What it means

Returned by POST /api/gateway/restart when h.RestartGateway() fails outside precondition validation. Preconditions that merely fail (no default model, bad credentials) are mapped to 400 precondition_failed with a reason; this 500 wraps infrastructure failures from gateway.go:1293-1352: 'failed to validate gateway start conditions' (config unreadable), 'refuse to restart non-gateway process (PID %d)' (PID-reuse guard), 'failed to stop gateway: ...' (old process ignored SIGTERM through the grace period and survived SIGKILL window, or 'existing gateway did not exit before restart'), or 'failed to start gateway: ...' (binary/config/pipe problems as in error 905).

Source

Thrown at web/backend/api/gateway.go:1385

// handleGatewayRestart stops the gateway (if running) and starts a new instance.
//
//	POST /api/gateway/restart
func (h *Handler) handleGatewayRestart(w http.ResponseWriter, r *http.Request) {
	pid, err := h.RestartGateway()
	if err != nil {
		// Check if it's a precondition failed error
		var precondErr *preconditionFailedError
		if errors.As(err, &precondErr) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]any{
				"status":  "precondition_failed",
				"message": precondErr.reason,
			})
			return
		}
		http.Error(w, fmt.Sprintf("Failed to restart gateway: %v", err), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]any{
		"status": "ok",
		"pid":    pid,
	})
}

// handleGatewayClearLogs clears the in-memory gateway log buffer.
//
//	POST /api/gateway/logs/clear
func (h *Handler) handleGatewayClearLogs(w http.ResponseWriter, r *http.Request) {
	gateway.logs.Clear()

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]any{

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Read the wrapped message to branch: stop failures, refuse-guard, config, or binary issues each have different fixes
  2. For 'did not exit before restart', retry POST /api/gateway/restart once - the second attempt starts from a cleared state
  3. For 'refuse to restart non-gateway process', inspect the PID with ps and restart the web backend to reset tracked state
  4. For config/binary causes, apply the fixes from errors 902/905, then retry
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: config loads (GET /api/config ok) is the cheap validation;
// readiness reasons arrive as 400 precondition_failed with a message.
const cfgOk = (await fetch('/api/config')).ok;
if (!cfgOk) throw new Error('fix config file before restarting gateway');

Try / catch

for (let attempt = 0; attempt < 3; attempt++) {
  const res = await fetch('/api/gateway/restart', {method: 'POST'});
  if (res.ok) return res.json();
  if (res.status === 400) {
    const body = await res.json();            // {status:'precondition_failed', message}
    throw new Error('Fix preconditions first: ' + body.message);   // not retryable
  }
  const text = await res.text();
  if (text.includes('refuse to restart non-gateway process')) throw new Error(text); // not retryable
  await sleep(2000 * (attempt + 1));          // stop/start infra failure: backoff and retry
}

Prevention

When it happens

Trigger: Hung gateway that does not exit within gatewayRestartGracePeriod and even survives the SIGKILL window (uninterruptible D-state); PID reuse triggering the refuse guard; picoclaw binary missing so the start half fails after a successful stop; corrupt config file failing the initial validation.

Common situations: Gateway wedged on a dead network mount after config changes; automation restarting immediately after a config swap; containers where the gateway ignores signals because PID 1 does not forward them.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/20aa5fb26365a414. Report an issue: GitHub.