moeru-ai/airi · error · Error

updateUser failed

Error message

updateUser failed

What it means

Thrown by updateUserProfile when better-auth's client.updateUser returns an error. The body only includes name and/or image when those args are defined. The fallback message 'updateUser failed' is used only when the server error lacks a message. Common server-side causes: name validation failure, image URL rejected, or rate limiting.

Source

Thrown at apps/ui-server-auth/src/modules/profile.ts:129

 * Update the signed-in user's display name and/or avatar.
 *
 * Use when:
 * - Saving the "display name" form on the profile page.
 *
 * Expects:
 * - Caller has already trimmed `name` and confirmed it's non-empty.
 * - `image` is either an absolute URL or `null` (clear).
 */
export async function updateUserProfile(args: UpdateUserProfileArgs): Promise<void> {
  const client = getAuthClient(args)
  const body: { name?: string, image?: string | null } = {}
  if (args.name !== undefined)
    body.name = args.name
  if (args.image !== undefined)
    body.image = args.image
  const { error } = await client.updateUser(body)
  if (error)
    throw new Error(error.message ?? 'updateUser failed')
}

/**
 * Change the signed-in user's password using their current credential.
 *
 * Use when:
 * - User is signed in and wants to rotate their password from the profile
 *   page (not the forgot-password email flow).
 *
 * Expects:
 * - The user has a `credential` account; social-only users get a server-side
 *   error which surfaces as a thrown `Error` here.
 */
export async function changePassword(args: ChangePasswordArgs): Promise<void> {
  const client = getAuthClient(args)
  const { error } = await client.changePassword({
    currentPassword: args.currentPassword,
    newPassword: args.newPassword,

View on GitHub (pinned to 27111382b4)

Solutions

  1. Trim name and confirm non-empty before calling (the docstring expects the caller to have done this).
  2. Ensure image is an absolute URL or null (null clears it); reject relative paths client-side.
  3. Read error.message for the server's specific reason and surface it to the form field.
  4. If the session lapsed, re-authenticate before retrying the update.
Defensive patterns

Strategy: validation

Validate before calling

const name = args.name?.trim()
if (args.name !== undefined && !name)
  throw new Error('Display name cannot be empty.')
if (args.image !== undefined && args.image !== null) {
  try { new URL(args.image) } catch { throw new Error('Image must be an absolute URL.') }
}
await updateUserProfile({ ...args, name })

Type guard

function isValidProfileUpdate(args) {
  if (args.name !== undefined && !args.name.trim()) return false
  if (args.image !== undefined && args.image !== null) {
    try { new URL(args.image) } catch { return false }
  }
  return true
}

Try / catch

try {
  await updateUserProfile(args)
} catch (e) {
  // e.message carries the server reason; map to the offending form field
}

Prevention

When it happens

Trigger: Saving the profile form with a name the server rejects (too long, banned word); passing an image that is not an absolute URL or that fails server-side upload validation; the session expired between load and save so updateUser 401s.

Common situations: User edits display name to an empty/whitespace string after the caller skipped trimming; avatar URL is relative or malformed; concurrent sign-out invalidated the session; server-side image processing failed.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/47c3400c6a8f8fe6. Report an issue: GitHub.