{"record":{"id":"41af444ecec10dd0","repo":"immich-app/immich","slug":"may-not-request-original-file","errorCode":null,"errorMessage":"May not request original file","messagePattern":"May not request original file","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"server/src/services/asset-media.service.ts","lineNumber":259,"sourceCode":"    const path = editedPath ?? originalPath!;\n\n    return new ImmichFileResponse({\n      path,\n      fileName: getFileNameWithoutExtension(originalFileName) + getFilenameExtension(path),\n      contentType: mimeTypes.lookup(path),\n      cacheControl: CacheControl.PrivateWithCache,\n    });\n  }\n\n  async viewThumbnail(\n    auth: AuthDto,\n    id: string,\n    dto: AssetMediaOptionsDto,\n  ): Promise<ImmichFileResponse | AssetMediaRedirectResponse> {\n    await this.requireAccess({ auth, permission: Permission.AssetView, ids: [id] });\n\n    if (dto.size === AssetMediaSize.Original) {\n      throw new BadRequestException('May not request original file');\n    }\n\n    if (auth.sharedLink) {\n      dto.edited = true;\n    }\n\n    const size = (dto.size ?? AssetMediaSize.THUMBNAIL) as unknown as AssetFileType;\n    const { originalPath, originalFileName, path } = await this.assetRepository.getForThumbnail(\n      id,\n      size,\n      dto.edited ?? false,\n    );\n\n    if (size === AssetFileType.FullSize && mimeTypes.isWebSupportedImage(originalPath) && !dto.edited) {\n      // use original file for web supported images\n      return { targetSize: 'original' };\n    }\n","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/asset-media.service.ts#L241-L277","documentation":"Thrown by AssetMediaService.viewThumbnail when dto.size === AssetMediaSize.Original. The thumbnail endpoint exists to serve downscaled previews/full-size renditions, never the source file; requesting the original here is explicitly rejected. The original must be fetched via the dedicated original endpoint (the DTO itself notes 'original' is deprecated for this route).","triggerScenarios":"GET /assets/:id/thumbnail?size=original — the client requests the unmodified source through the thumbnail route.","commonSituations":"Older SDK versions that still send size=original to this endpoint; client code assuming one endpoint fits all sizes; migration from a previous API version that allowed it.","solutions":["Use the original endpoint (GET /assets/:id/original) to fetch the source file","Request a valid thumbnail size (preview, fullsize, thumbnail) on this endpoint","Upgrade the client SDK to a version that targets the correct endpoint"],"exampleFix":"// before\nawait sdk.viewThumbnail(id, { size: 'original' }); // 400\n// after\nawait sdk.getOriginalAsset(id); // dedicated original endpoint","handlingStrategy":"validation","validationCode":"// Route original requests to the dedicated endpoint\nconst size = requestedSize === 'original' ? null : requestedSize;\nif (requestedSize === 'original') {\n  return sdk.getOriginalAsset(id);\n}\nreturn sdk.viewThumbnail(id, { size });","typeGuard":"function isValidThumbnailSize(s: string): boolean {\n  return ['thumbnail','preview','fullsize'].includes(s);\n}","tryCatchPattern":null,"preventionTips":["Never send size=original to the thumbnail endpoint — use the original endpoint","Upgrade SDK to a version that splits original into its own route","Validate the requested size against the route's allowed set client-side"],"tags":["asset","thumbnail","validation","deprecated","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}