iOfficeAI/AionUi · error
[WebUI] /api/webui/reset-password returned no new_password
Error message
[WebUI] /api/webui/reset-password returned no new_password
What it means
Thrown when POST /api/webui/reset-password succeeds (2xx) but the JSON response contains no new_password field (neither data.new_password nor top-level new_password). The seeding flow cannot capture a credential to show the user.
Source
Thrown at packages/desktop/src/process/bridge/webuiBridge.ts:74
}
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();
const handle = await startDesktopWebUI({
port: params?.port,
allowRemote: params?.allowRemote,
});
ipcBridge.webui.statusChanged.emit({View on GitHub (pinned to 711aa0550e)
Solutions
- Inspect the actual response body (add a log of resetJson before throwing)
- Align the desktop client with the backend's current response schema (data.new_password vs new_password)
- Pin or upgrade together desktop and aioncore backend versions so schemas match
- Add backend-side contract tests for the reset-password response shape
Example fix
// before
const newPassword = resetJson.data?.new_password ?? resetJson.new_password;
// after (also accept token-style shapes and log for diagnosis)
const newPassword = resetJson.data?.new_password ?? resetJson.new_password ?? resetJson.data?.password;
if (!newPassword) {
console.error('[WebUI] reset-password unexpected payload:', JSON.stringify(resetJson));
throw new Error('[WebUI] /api/webui/reset-password returned no new_password');
} Defensive patterns
Strategy: type-guard
Validate before calling
const json = (await resetRes.json()) as { data?: { new_password?: string } };
if (!json.data?.new_password) { /* log payload, surface schema mismatch clearly */ } Type guard
function hasNewPassword(v: unknown): v is { data: { new_password: string } } {
return typeof (v as { data?: { new_password?: unknown } })?.data?.new_password === 'string';
} Try / catch
catch (err) { log.error('[WebUI] reset payload:', err.message, rawBody); throw err; } Prevention
- Share response types between desktop and backend packages
- Log raw payloads when shape checks fail
- Add schema tests for auth/reset endpoints
When it happens
Trigger: Backend returns 200 with a differently shaped payload, e.g. {data:{}} or a renamed field, so newPassword is undefined.
Common situations: Backend API version drift where the response schema changed (field renamed, nesting moved), or an error payload returned with 200 status.
Related errors
- reset-password returned no new_password
- [WebUI] /api/webui/reset-password returned ${resetRes.status
- [WebUI] Cannot start: aioncore is not running (globalThis.__
- [WebUI] /api/auth/status returned ${statusRes.status}
AI-assisted analysis of iOfficeAI/AionUi@711aa0550e (2026-08-28).
Data as JSON: /api/errors/69cdb1809e6ab47b.
Report an issue: GitHub.