immich-app/immich · error · UnauthorizedException
Invalid password
Error message
Invalid password
What it means
SharedLink.login compares the submitted dto.password with the stored shared link password. On mismatch it throws UnauthorizedException('Invalid password'), meaning the link is password-protected but the supplied password is wrong.
Solutions
- Re-enter the password, confirming exact case and no extra whitespace.
- Ask the link owner for the current password (it may have been changed).
- Owner can reset the password via the shared link edit endpoint and share the new one.
Example fix
// before
await api.sharedLinkLogin(key, { password: savedPassword }); // stale
// after
const password = await promptUser('Shared link password');
await api.sharedLinkLogin(key, { password: password.trim() }); Defensive patterns
Strategy: try-catch
Try / catch
try {
return await api.sharedLinkLogin(key, { password });
} catch (e) {
if (e.status === 401 && e.message === 'Invalid password') {
// re-prompt the user; do not retry the same password in a loop
} else {
throw e;
}
} Prevention
- Trim passwords before submitting (avoid pasted whitespace).
- Re-prompt on failure instead of looping with a stored password.
- Fetch a fresh password from the owner if it may have rotated.
When it happens
Trigger: POST to the shared-link login endpoint with dto.password !== sharedLink.password for a password-protected link.
Common situations: User mistypes the password; owner rotated the link password and the visitor uses the old one; stale client cached the previous password; case/whitespace differences when pasting.
Related errors
- Password required
- Invalid API key
- Invalid JWT Token
- Missing JWT Token
- Shared link is not password protected
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/8d8b711dae91bcc4.
Report an issue: GitHub.
Appendix: 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 e55ac299a4)