immich-app/immich · warning · UnauthorizedException

Invalid password

Error message

Invalid password

What it means

SharedLinkService.login() compares the submitted password to the stored shared-link password with a strict equality (password !== dto.password). A mismatch throws UnauthorizedException 'Invalid password' (shared-link.service.ts:40, HTTP 401). Note the comparison is plain string equality, not constant-time.

Source

Thrown at server/src/services/shared-link.service.ts:40

      .getAll({ userId: auth.user.id, id, albumId })

      .then((links) => links.map((link) => mapSharedLink(link, { stripAssetMetadata: false })));
  }

  async login(auth: AuthDto, dto: SharedLinkLoginDto) {
    if (!auth.sharedLink) {
      throw new ForbiddenException();
    }

    const sharedLink = await this.findOrFail(auth.user.id, auth.sharedLink.id);
    const { id, password } = sharedLink;

    if (!password) {
      throw new BadRequestException('Shared link is not password protected');
    }

    if (password !== dto.password) {
      throw new UnauthorizedException('Invalid password');
    }

    return {
      sharedLink: mapSharedLink(sharedLink, { stripAssetMetadata: !sharedLink.showExif }),
      token: this.asToken({ id, password }),
    };
  }

  async getMine(auth: AuthDto, authTokens: string[]) {
    if (!auth.sharedLink) {
      throw new ForbiddenException();
    }

    const sharedLink = await this.findOrFail(auth.user.id, auth.sharedLink.id);
    const { id, password } = sharedLink;

    if (password && !authTokens.includes(this.asToken({ id, password }))) {
      throw new UnauthorizedException('Password required');

View on GitHub (pinned to 199723261c)

Solutions

  1. Re-enter the password carefully, matching case and without surrounding whitespace.
  2. If forgotten, ask the link owner to share the current password or to reset it via PATCH /shared-links/:id.
  3. On the client, trim() the input only if the owner's stored value is also trimmed (otherwise do not trim).

Example fix

// before
await login({ password: 'secret ' }); // trailing space
// after
await login({ password: 'secret' });
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  await sharedLinkApi.login({ password });
} catch (e) {
  if (e instanceof UnauthorizedException && /invalid password/i.test(e.message)) {
    showFieldError('password', 'Incorrect password. Try again.');
  } else throw e;
}

Prevention

When it happens

Trigger: Submitting the wrong password for a password-protected shared link on the login endpoint — typo, wrong case, or an outdated password after the owner changed it.

Common situations: User mistyping the password, copy-paste with trailing whitespace, or the link owner rotated the password while a viewer had a stale one.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/8d8b711dae91bcc4. Report an issue: GitHub.