{"record":{"id":"8d8b711dae91bcc4","repo":"immich-app/immich","slug":"invalid-password","errorCode":null,"errorMessage":"Invalid password","messagePattern":"Invalid password","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server/src/services/shared-link.service.ts","lineNumber":40,"sourceCode":"      .getAll({ userId: auth.user.id, id, albumId })\n\n      .then((links) => links.map((link) => mapSharedLink(link, { stripAssetMetadata: false })));\n  }\n\n  async login(auth: AuthDto, dto: SharedLinkLoginDto) {\n    if (!auth.sharedLink) {\n      throw new ForbiddenException();\n    }\n\n    const sharedLink = await this.findOrFail(auth.user.id, auth.sharedLink.id);\n    const { id, password } = sharedLink;\n\n    if (!password) {\n      throw new BadRequestException('Shared link is not password protected');\n    }\n\n    if (password !== dto.password) {\n      throw new UnauthorizedException('Invalid password');\n    }\n\n    return {\n      sharedLink: mapSharedLink(sharedLink, { stripAssetMetadata: !sharedLink.showExif }),\n      token: this.asToken({ id, password }),\n    };\n  }\n\n  async getMine(auth: AuthDto, authTokens: string[]) {\n    if (!auth.sharedLink) {\n      throw new ForbiddenException();\n    }\n\n    const sharedLink = await this.findOrFail(auth.user.id, auth.sharedLink.id);\n    const { id, password } = sharedLink;\n\n    if (password && !authTokens.includes(this.asToken({ id, password }))) {\n      throw new UnauthorizedException('Password required');","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/shared-link.service.ts#L22-L58","documentation":"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.","triggerScenarios":"POST to the shared-link login endpoint with dto.password !== sharedLink.password for a password-protected link.","commonSituations":"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.","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."],"exampleFix":"// before\nawait api.sharedLinkLogin(key, { password: savedPassword }); // stale\n// after\nconst password = await promptUser('Shared link password');\nawait api.sharedLinkLogin(key, { password: password.trim() });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await api.sharedLinkLogin(key, { password });\n} catch (e) {\n  if (e.status === 401 && e.message === 'Invalid password') {\n    // re-prompt the user; do not retry the same password in a loop\n  } else {\n    throw e;\n  }\n}","preventionTips":["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."],"tags":["shared-link","password","authentication","unauthorized"],"backgroundTag":"authentication-required","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}