{"record":{"id":"cd770346435ac719","repo":"hcengineering/platform","slug":"no-screen-access-granted","errorCode":null,"errorMessage":"No screen access granted","messagePattern":"No screen access granted","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"desktop/src/ui/screenShare.ts","lineNumber":44,"sourceCode":"    return\n  }\n\n  if (navigator.mediaDevices.getDisplayMedia === undefined) {\n    throw new DeviceUnsupportedError('getDisplayMedia not supported')\n  }\n\n  navigator.mediaDevices.getDisplayMedia = async (opts?: DisplayMediaStreamOptions): Promise<MediaStream> => {\n    if (opts === undefined) {\n      throw new Error('opts must be provided')\n    }\n\n    const ipcMain = ipcMainExposed()\n    const sources = await ipcMain.getScreenSources()\n\n    const hasAccess = await ipcMain.getScreenAccess()\n    if (!hasAccess) {\n      log.error('No screen access granted')\n      throw new Error('No screen access granted')\n    }\n\n    return await new Promise<MediaStream>((resolve, reject) => {\n      let wasSelected = false\n\n      showPopup(\n        love.component.SelectScreenSourcePopup,\n        {\n          sources\n        },\n        'top',\n        () => {\n          if (!wasSelected) {\n            reject(new Error('No source selected'))\n          }\n        },\n        (val) => {\n          if (val != null) {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/desktop/src/ui/screenShare.ts#L26-L62","documentation":"The mail service endpoint in services/mail/pod-mail/src/main.ts responds with HTTP 400 and { err: \"'from' is missing\" } when the send-mail request body lacks the 'fromAddress' sender field. It is the last of handleSendMail's required-field checks; reaching it means text/html, subject, and to were all present but 'from' was absent. The service needs 'from' to build the SendMailOptions passed to the underlying mail transport.","triggerScenarios":"POSTing to the mail endpoint with body content, subject, and 'to' but no 'from' property, or 'from' set to undefined/null.","commonSituations":"A service account or sender address configured via env var that is unset in the deployment; refactored callers that dropped the 'from' field; default-sender logic that silently yields undefined.","solutions":["Add the sender address as 'from' in the request body.","If the app has a system sender, configure it (e.g. MAIL_FROM env var) and inject it server-side into every request.","Fail fast at startup if the configured sender address is missing rather than at send time.","Centralize payload construction in one helper that always sets 'from'."],"exampleFix":"// before\nconst body = { to, subject, text, from: process.env.MAIL_FROM } // env unset -> undefined dropped\n// after\nconst from = process.env.MAIL_FROM\nif (!from) throw new Error('MAIL_FROM is not configured')\nconst body = { to, subject, text, from }","handlingStrategy":"validation","validationCode":"const from = process.env.MAIL_FROM\nif (!from) throw new Error('MAIL_FROM is not configured; cannot send mail')","typeGuard":"function hasSender(body: unknown): body is { from: string; [k: string]: unknown } {\n  return typeof body === 'object' && body !== null && typeof (body as any).from === 'string' && (body as any).from.length > 0\n}","tryCatchPattern":"const res = await fetch(mailUrl, { method: 'POST', body })\nif (res.status === 400) {\n  const { err } = await res.json()\n  if (err === \"'from' is missing\") {\n    // abort with a configuration error — this payload can never succeed as-is\n  }\n}","preventionTips":["Configure a default system sender via env var and validate it at service startup, not at send time.","Centralize 'from' injection in a single request-builder helper.","Add a smoke test that sends to a mail trap in staging to catch missing sender config early."],"tags":["http-400","validation","missing-field","mail","configuration"],"backgroundTag":"missing-request-field","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}