immich-app/immich · warning · BadRequestException
Shared link is not password protected
Error message
Shared link is not password protected
What it means
In SharedLinkService.login(), after the shared link is resolved, if it has no password set the service throws BadRequestException 'Shared link is not password protected' (shared-link.service.ts:36, HTTP 400). Logging into a link that requires no password is a category error.
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 199723261c)
Solutions
- Before showing a password prompt or calling login, check the shared link's password-protected flag from getMine/get and skip login for unprotected links.
- If the link was meant to be protected, set a password via PATCH /shared-links/:id (update).
- Clear client-side state that assumes a password flow for this link.
Example fix
// before - always login
await sharedLinkApi.login({ password });
// after - only when protected
if (sharedLink.password) {
await sharedLinkApi.login({ password });
} Defensive patterns
Strategy: validation
Validate before calling
// Resolve the link first; only login if it is password-protected.
const link = await sharedLinkApi.getMine();
if (!link.password) {
// unprotected link — no login needed, proceed directly
return link;
}
return sharedLinkApi.login({ password }); Type guard
const isPasswordProtected = (link: { password?: string | null }): boolean => !!link.password; Try / catch
try {
await sharedLinkApi.login(dto);
} catch (e) {
if (e instanceof BadRequestException && /not password protected/i.test(e.message)) {
// skip login; this link needs no password
return sharedLinkApi.getMine();
} else throw e;
} Prevention
- Gate the password prompt on the link's password flag from getMine/get.
- Re-fetch link metadata if the owner may have changed protection.
When it happens
Trigger: POST to the shared-link login endpoint for a shared link whose password field is null/empty. The caller should not attempt a password exchange for an unprotected link.
Common situations: Frontend always invoking login regardless of whether the link is password-protected, stale client state assuming a password prompt, or a link whose password was cleared via update but the client still tries to log in.
Related errors
- Wrong password
- Shared link access is only allowed in combination with an al
- Invalid password
- Password required
- Invalid albumId
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/6f4b4755f460df58.
Report an issue: GitHub.