sipeed/picoclaw · error

Request failed with status ${res.status}

Error message

Request failed with status ${res.status}

What it means

This message is the fallback error string produced by readLauncherAuthError in web/frontend/src/api/launcher-auth.ts:74 when POST /api/auth/setup fails and the response body is not JSON containing an error field; it is then re-thrown by handleSave via throw new Error(result.error) at web/frontend/src/components/config/config-page.tsx:684 when result.ok is false. It means the dashboard-password setup endpoint rejected the request with an HTTP error status and no readable error message.

Source

Thrown at web/frontend/src/components/config/config-page.tsx:684

          trustedProxyCIDRsText: (
            savedLauncherConfig.trusted_proxy_cidrs ?? []
          ).join("\n"),
          dashboardPassword: "",
          dashboardPasswordConfirm: "",
        }
        savedLauncherForm = parsedLauncher
        setLauncherForm(parsedLauncher)
        setLauncherBaseline(parsedLauncher)
        queryClient.setQueryData(
          ["system", "launcher-config"],
          savedLauncherConfig,
        )
      }

      if (launcherPasswordDirty) {
        const result = await postLauncherDashboardSetup(password, confirm)
        if (!result.ok) {
          throw new Error(result.error)
        }

        const clearedLauncherForm = savedLauncherForm ?? {
          ...launcherForm,
          dashboardPassword: "",
          dashboardPasswordConfirm: "",
        }
        setLauncherForm(clearedLauncherForm)
        if (savedLauncherForm) {
          setLauncherBaseline(savedLauncherForm)
        }
      }

      if (autoStartDirty) {
        if (!autoStartSupported) {
          throw new Error(t("pages.config.autostart_unsupported"))
        }
        const status = await updateAutoStartEnabled(autoStartEnabled)

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Open the network tab, find POST /api/auth/setup, and read the status code — the message embeds it (e.g. 409)
  2. For 409: the password is already configured; use the change/update password flow rather than setup
  3. For 400: choose a stronger password (server-side rules may exceed the client's 8-char minimum) and ensure both fields match
  4. For 502/HTML responses: fix the reverse proxy routing so /api/auth reaches the launcher backend
Defensive patterns

Strategy: try-catch

Validate before calling

const result = await postLauncherDashboardSetup(password, confirm)
if (!result.ok) {
  // result.error may be 'Request failed with status N' when the body had no JSON error
  console.warn("setup failed:", result.error)
}

Type guard

type SetupResult = { ok: true } | { ok: false; error: string }
function isSetupFailure(r: SetupResult): r is Extract<SetupResult, { ok: false }> {
  return !r.ok
}

Try / catch

try {
  const result = await postLauncherDashboardSetup(password, confirm)
  if (isSetupFailure(result)) {
    setError(result.error) // includes the HTTP status when the server sent no JSON error
  }
} catch (err) {
  setError(err instanceof Error ? err.message : "Setup request failed")
}

Prevention

When it happens

Trigger: POST /api/auth/setup returns 400 (password too weak/confirmation mismatch server-side), 409 (dashboard password already set — setup is one-time), 401/403 (auth constraints), or a proxy 502 with an HTML body, all without a JSON {error} payload.

Common situations: Trying to 'set' the password again after initial setup instead of using the change-password flow; reverse proxy intercepting /api/auth with an HTML error page; backend version whose setup endpoint validates differently than the frontend (e.g. stricter length); session cookie missing.

Related errors


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