iOfficeAI/AionUi · error

[WebUI] /api/webui/reset-password returned ${resetRes.status

Error message

[WebUI] /api/webui/reset-password returned ${resetRes.status}

What it means

Thrown when POST /api/webui/reset-password on the local backend returns a non-2xx status during WebUI initial-password seeding. The HTTP status is included in the message.

Source

Thrown at packages/desktop/src/process/bridge/webuiBridge.ts:69

 */
async function maybeSeedInitialPassword(): Promise<void> {
  const port = getBackendPort();
  if (!port) {
    throw new Error('[WebUI] Cannot start: aioncore is not running (globalThis.__backendPort unset)');
  }
  const statusRes = await fetch(`http://127.0.0.1:${port}/api/auth/status`);
  if (!statusRes.ok) {
    throw new Error(`[WebUI] /api/auth/status returned ${statusRes.status}`);
  }
  const statusJson = (await statusRes.json()) as { needs_setup?: boolean; data?: { needs_setup?: boolean } };
  const needsSetup = statusJson.needs_setup ?? statusJson.data?.needs_setup ?? false;
  if (!needsSetup) {
    setDesktopWebUIInitialPassword(undefined);
    return;
  }
  const resetRes = await fetch(`http://127.0.0.1:${port}/api/webui/reset-password`, { method: 'POST' });
  if (!resetRes.ok) {
    throw new Error(`[WebUI] /api/webui/reset-password returned ${resetRes.status}`);
  }
  const resetJson = (await resetRes.json()) as { data?: { new_password?: string }; new_password?: string };
  const newPassword = resetJson.data?.new_password ?? resetJson.new_password;
  if (!newPassword) {
    throw new Error('[WebUI] /api/webui/reset-password returned no new_password');
  }
  setDesktopWebUIInitialPassword(newPassword);
}

export function initWebuiBridge(): void {
  ipcBridge.webui.getStatus.provider(async () => {
    const snapshot = getDesktopWebUIStatus();
    const adminUsername = await fetchAdminUsername();
    return { ...snapshot, adminUsername };
  });

  ipcBridge.webui.start.provider(async (params) => {
    await maybeSeedInitialPassword();

View on GitHub (pinned to 711aa0550e)

Solutions

  1. Re-check /api/auth/status — if needs_setup flipped to false, seeding should be skipped, not reset
  2. curl -X POST the reset-password endpoint and read the response body for the backend's error detail
  3. Check backend logs for the failed reset (DB errors, validation errors)
  4. Confirm backend version compatibility with the desktop client
Defensive patterns

Strategy: retry

Validate before calling

const status = await fetch(`http://127.0.0.1:${port}/api/auth/status`).then((r) => r.json());
if (!status.needs_setup && !status.data?.needs_setup) { /* skip reset: nothing to seed */ }

Try / catch

catch (err) {
  if (/reset-password returned/.test(err.message)) {
    const s = await fetchStatus(); // maybe setup completed elsewhere
    if (!needsSetup(s)) return; // benign race
  }
  throw err;
}

Prevention

When it happens

Trigger: The backend responds 4xx/5xx to the unauthenticated reset-password request — e.g. the endpoint rejects the call because setup is not actually pending, or the backend errors while resetting.

Common situations: Race where another process already completed setup between the status check and the reset call, backend version mismatch removing/changing the endpoint, or backend internal error (DB locked/corrupt).

Related errors


AI-assisted analysis of iOfficeAI/AionUi@711aa0550e (2026-08-28). Data as JSON: /api/errors/1bb02a55fcad44f7. Report an issue: GitHub.