immich-app/immich · warning · BadRequestException

Shared link is not password protected

Error message

Shared link is not password protected

What it means

SharedLink.login authenticates a visitor against a password-protected shared link. If the link has no password stored, asking for a password login is invalid and a BadRequestException is thrown — the link is already openly accessible.

Solutions

  1. Skip the password step and access the shared link directly — no password is needed.
  2. Refresh link metadata client-side to detect that password protection is off.
  3. If a password is desired, have the owner add one via the shared link edit endpoint.

Example fix

// before
await api.sharedLinkLogin(shareKey, { password }); // link has no password
// after
const link = await api.getSharedLink(shareKey);
if (link.requiresPassword) await api.sharedLinkLogin(shareKey, { password });
Defensive patterns

Strategy: validation

Validate before calling

if (!linkData.requiresPassword) {
  // open link: access directly, skip password login
  return accessSharedLink(shareKey);
}

Type guard

const needsPassword = (link) =>
  typeof link === 'object' && link !== null && typeof link.hasPassword === 'boolean' && link.hasPassword;

Try / catch

try {
  return await api.sharedLinkLogin(key, { password });
} catch (e) {
  if (e.status === 400 && /not password protected/.test(e.message)) {
    return accessSharedLink(key); // no password needed
  }
  throw e;
}

Prevention

When it happens

Trigger: POST to the shared-link access/login endpoint for a link whose sharedLink.password is null, i.e. submitting dto.password for a link that was created without a password.

Common situations: Client always shows a password prompt by default; stale client state where the link was edited to remove the password but the UI still asks for one; automated clients unconditionally posting a password.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/6f4b4755f460df58. Report an issue: GitHub.

Appendix: source

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

@Injectable()
export class SharedLinkService extends BaseService {
  async getAll(auth: AuthDto, { id, albumId }: SharedLinkSearchDto): Promise<SharedLinkResponseDto[]> {
    return this.sharedLinkRepository
      .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);

View on GitHub (pinned to e55ac299a4)