sipeed/picoclaw · error

Failed to validate gateway start conditions: %v

Error message

Failed to validate gateway start conditions: %v

What it means

Returned by POST /api/gateway/start when a live PID file exists and h.gatewayStartReady() returns an error. Reading gateway.go:371-375, the only error path in gatewayStartReady is config.LoadConfig(h.configPath) failing - the picoclaw config file cannot be read or parsed. This is deliberately distinct from the 400 precondition_failed branch, which handles semantic problems (no default model, invalid model, missing credentials, unreachable local model). A 500 here means the config file itself is unreadable or syntactically broken.

Source

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

		}
	}()

	return pid, nil
}

// handleGatewayStart starts the picoclaw gateway subprocess.
//
//	POST /api/gateway/start
func (h *Handler) handleGatewayStart(w http.ResponseWriter, r *http.Request) {
	// Check PID file first to detect an already-running gateway.
	pidData := h.sanitizeGatewayPidData(ppid.ReadPidFileWithCheck(globalConfigDir()), nil)
	if pidData != nil {
		pid := pidData.PID
		gateway.mu.Lock()
		ready, reason, err := h.gatewayStartReady()
		if err != nil {
			gateway.mu.Unlock()
			http.Error(
				w,
				fmt.Sprintf("Failed to validate gateway start conditions: %v", err),
				http.StatusInternalServerError,
			)
			return
		}
		if !ready {
			gateway.mu.Unlock()
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]any{
				"status":  "precondition_failed",
				"message": reason,
			})
			return
		}
		_, err = h.startGatewayLocked("starting", pid)
		if err != nil {

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Call GET /api/config - it hits the same config.LoadConfig and its error text shows the exact parse/read failure
  2. Fix the reported syntax error, or restore the config file from backup
  3. Verify the config file is readable by the user running the backend process (check ownership and mode)
  4. Retry POST /api/gateway/start once the config loads cleanly
Defensive patterns

Strategy: validation

Validate before calling

// Probe config loadability before starting the gateway -
// GET /api/config exercises the same config.LoadConfig call.
const probe = await fetch('/api/config');
if (!probe.ok) {
  const detail = await probe.text();   // e.g. the YAML/JSON parse error
  throw new Error('config file is broken, fix before gateway start: ' + detail);
}

Try / catch

const res = await fetch('/api/gateway/start', {method: 'POST'});
if (res.status === 500) {
  const text = await res.text();
  if (text.startsWith('Failed to validate gateway start conditions')) {
    // infrastructure failure: config unreadable -> route user to config repair, do NOT retry blindly
    await router.push('/settings/config');
  }
  throw new Error(text);
}

Prevention

When it happens

Trigger: config.json/yaml was hand-edited and left with a syntax error while the launcher runs; the config file was deleted, moved, or truncated; file permissions changed so the backend user can no longer read it; the config sits on a network mount that just dropped.

Common situations: Editing the config in an external editor with an unsaved/invalid intermediate state; running the web backend under a different user (systemd unit, container) than the one owning the config file; a crashed disk-full write left a zero-length config.

Related errors


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