{"record":{"id":"3334301cb923d4df","repo":"immich-app/immich","slug":"invalid-share-slug","errorCode":null,"errorMessage":"Invalid share slug","messagePattern":"Invalid share slug","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server/src/services/auth.service.ts","lineNumber":515,"sourceCode":"\n  async validateSharedLinkKey(key: string | string[]): Promise<AuthDto> {\n    key = Array.isArray(key) ? key[0] : key;\n\n    const bytes = Buffer.from(key, key.length === 100 ? 'hex' : 'base64url');\n    const sharedLink = await this.sharedLinkRepository.getByKey(bytes);\n    if (!this.isValidSharedLink(sharedLink)) {\n      throw new UnauthorizedException('Invalid share key');\n    }\n\n    return { user: sharedLink.user, sharedLink };\n  }\n\n  async validateSharedLinkSlug(slug: string | string[]): Promise<AuthDto> {\n    slug = Array.isArray(slug) ? slug[0] : slug;\n\n    const sharedLink = await this.sharedLinkRepository.getBySlug(slug);\n    if (!this.isValidSharedLink(sharedLink)) {\n      throw new UnauthorizedException('Invalid share slug');\n    }\n\n    return { user: sharedLink.user, sharedLink };\n  }\n\n  private isValidSharedLink(\n    sharedLink?: AuthSharedLink & { user: AuthUser | null },\n  ): sharedLink is AuthSharedLink & { user: AuthUser } {\n    return !!sharedLink?.user && (!sharedLink.expiresAt || new Date(sharedLink.expiresAt) > new Date());\n  }\n\n  private async validateApiKey(key: string): Promise<AuthDto> {\n    const hashed = this.cryptoRepository.hashSha256(key);\n    const apiKey = await this.apiKeyRepository.getKey(hashed);\n    if (apiKey?.user) {\n      return {\n        user: apiKey.user,\n        apiKey,","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/immich-app/immich/blob/f48d4b332127ad365ba256108799ca8f571d2dd5/server/src/services/auth.service.ts#L497-L533","documentation":"Shared links can be addressed by a human-readable slug instead of a key. The service resolves the slug via sharedLinkRepository.getBySlug and applies the same validity check (exists, not expired). Failure yields UnauthorizedException.","triggerScenarios":"GET /share/<slug> where the slug does not match any existing share link, or the matching link has expired or been revoked.","commonSituations":"Typos in the slug; slug reused/renamed by the owner; share deleted after album/asset was unshared; expired link still bookmarked.","solutions":["Verify the exact slug with the owner and retry","Regenerate the share link and use the new slug","Ask the owner to extend the expiry","Check whether the share was deleted or the album removed"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (e) { if (e.status === 401 && e.message === 'Invalid share slug') { /* prompt for fresh link */ } }","preventionTips":["Bookmark links via the app, not hand-typed slugs","Monitor link expiry","Confirm slugs after renames"],"tags":["auth","shared-links","unauthorized"],"backgroundTag":"invalid-credentials","analyzedSha":"f48d4b332127ad365ba256108799ca8f571d2dd5","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}