{"record":{"id":"cf153981a5c77648","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-cf1539","errorCode":"error-invalid-user","errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/media/getS3FileUrl.ts","lineNumber":22,"sourceCode":"import { Meteor } from 'meteor/meteor';\n\nimport { canAccessRoomAsync } from '../../lib/authorization';\nimport { settings } from '../../settings';\nimport { UploadFS } from '../../ufs';\n\ndeclare module '@rocket.chat/ddp-client' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tinterface ServerMethods {\n\t\tgetS3FileUrl(fileId: string): string;\n\t}\n}\n\nMeteor.methods<ServerMethods>({\n\tasync getS3FileUrl(fileId) {\n\t\tcheck(fileId, String);\n\t\tconst uid = Meteor.userId();\n\t\tif (settings.get<boolean>('FileUpload_ProtectFiles') && !uid) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'sendFileMessage' });\n\t\t}\n\t\tconst file = await Uploads.findOneById(fileId);\n\t\tif (!file?.rid) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed');\n\t\t}\n\t\tconst room = await Rooms.findOneById(file.rid);\n\t\tif (uid && room && !(await canAccessRoomAsync(room, { _id: uid }))) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed');\n\t\t}\n\n\t\treturn UploadFS.getStore('AmazonS3:Uploads').getRedirectURL(file);\n\t},\n});\n","sourceCodeStart":4,"sourceCodeEnd":36,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/media/getS3FileUrl.ts#L4-L36","documentation":"getS3FileUrl resolves the caller via Meteor.userId(); when the workspace setting FileUpload_ProtectFiles is enabled and there is no logged-in user, it throws error-invalid-user. The details object misleadingly says method 'sendFileMessage' — a copy-paste artifact; match on the code, not the method detail. The method then returns a redirect URL from the AmazonS3:Uploads store, which is why anonymous access is blocked when protection is on.","triggerScenarios":"Calling getS3FileUrl(fileId) from an anonymous/guest context while FileUpload_ProtectFiles = true; also DDP calls after session expiry on protected workspaces.","commonSituations":"Embedding or hot-linking S3-hosted uploads in external pages or scripts without a session; enabling FileUpload_ProtectFiles on a workspace whose consumers were previously anonymous.","solutions":["Authenticate the client before requesting the URL","For external sharing, use the signed/upload token returned by the upload flow (file link tokens) rather than this method","Only if anonymous access is intentionally public, disable FileUpload_ProtectFiles — understand this removes protection for all uploads"],"exampleFix":"// before (anonymous call on a protected workspace)\nconst url = Meteor.call('getS3FileUrl', fileId);\n\n// after\nif (!Meteor.userId()) {\n  // settings.get('FileUpload_ProtectFiles') is true: login first\n  throw new Meteor.Error('error-invalid-user', 'Login required');\n}\nconst url = await Meteor.callAsync('getS3FileUrl', fileId);","handlingStrategy":"validation","validationCode":"if (!Meteor.userId()) {\n  // FileUpload_ProtectFiles blocks anonymous getS3FileUrl: login first\n  throw new Meteor.Error('error-invalid-user', 'Login required');\n}\nconst url = await Meteor.callAsync('getS3FileUrl', fileId);","typeGuard":null,"tryCatchPattern":"try {\n  const url = await Meteor.callAsync('getS3FileUrl', fileId);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-invalid-user') {\n    // protected files need a session: authenticate and retry once\n    return;\n  }\n  throw err;\n}","preventionTips":["On protected workspaces, never resolve S3 URLs anonymously","Use the file-link tokens from the upload response for external sharing","Ignore the misleading 'sendFileMessage' method detail when matching this error"],"tags":["authentication","file-upload","s3","meteor-methods"],"backgroundTag":"authentication-required","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}