sipeed/picoclaw · error

Failed to load launcher config: %v

Error message

Failed to load launcher config: %v

What it means

Returned by GET /api/system/launcher-config when launcherconfig.Load of launcher-config.json (path derived via PathForAppConfig next to the app config) fails. From launcherconfig/config.go:102-124: a missing file is fine (server-flag fallback is returned); errors come from reading the file (permission, I/O), invalid JSON, or on-disk values failing Validate - port outside 1-65535, or a CIDR entry that net.ParseCIDR rejects.

Source

Thrown at web/backend/api/launcher_config.go:57

		port = launcherconfig.DefaultPort
	}
	return launcherconfig.Config{
		Port:                 port,
		Public:               h.serverPublic,
		AllowedCIDRs:         append([]string(nil), h.serverCIDRs...),
		AllowLocalhostBypass: h.serverAllowLocalhostBypass,
		TrustedProxyCIDRs:    append([]string(nil), h.serverTrustedProxyCIDRs...),
	}
}

func (h *Handler) loadLauncherConfig() (launcherconfig.Config, error) {
	return launcherconfig.Load(h.launcherConfigPath(), h.launcherFallbackConfig())
}

func (h *Handler) handleGetLauncherConfig(w http.ResponseWriter, r *http.Request) {
	cfg, err := h.loadLauncherConfig()
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to load launcher config: %v", err), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(launcherConfigPayload{
		Port:                 cfg.Port,
		Public:               cfg.Public,
		AllowedCIDRs:         append([]string(nil), cfg.AllowedCIDRs...),
		AllowLocalhostBypass: cfg.AllowLocalhostBypass,
		TrustedProxyCIDRs:    append([]string(nil), cfg.TrustedProxyCIDRs...),
	})
}

func (h *Handler) handleUpdateLauncherConfig(w http.ResponseWriter, r *http.Request) {
	var payload launcherConfigUpdatePayload
	if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
		http.Error(w, fmt.Sprintf("Invalid JSON: %v", err), http.StatusBadRequest)
		return

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Read the wrapped error: a JSON syntax error points at editing damage; a Validate error names the offending port or CIDR
  2. Fix the named field, or simply delete launcher-config.json - that is safe, the handler falls back to the server's startup flags
  3. Ensure the backend process can read the file (ownership and mode)
  4. Afterward use PUT /api/system/launcher-config for changes so values are always validated before persistence
Defensive patterns

Strategy: try-catch

Try / catch

let res = await fetch('/api/system/launcher-config');
if (res.status === 500) {
  const detail = await res.text();
  // File-side corruption cannot be fixed through the API - offer a reset action:
  if (confirm('launcher-config.json is unreadable (' + detail + '). Delete it on the server to restore defaults?')) {
    await serverSideResetLauncherConfig();   // rm the file; GET then falls back to startup flags
    res = await fetch('/api/system/launcher-config');
  }
}

Prevention

When it happens

Trigger: launcher-config.json hand-edited with a JSON typo; port edited to 0 or 70000; a CIDR written as a bare IP like "192.168.1.5" instead of "192.168.1.5/32"; file owned by root:0600 while the backend runs unprivileged.

Common situations: Sysadmins hand-editing the file instead of using the PUT endpoint; restoring a backup with wrong ownership; schema drift after version upgrades.

Related errors


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