{"record":{"id":"de6e83a7958deddb","repo":"hcengineering/platform","slug":"failed-to-load-server-config","errorCode":null,"errorMessage":"Failed to load server config","messagePattern":"Failed to load server config","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"desktop/src/ui/preload.ts","lineNumber":42,"sourceCode":"    const newPath = path.slice(1)\n    return `${host}${newPath}`\n  } else {\n    return `${host}${path}`\n  }\n}\n\nasync function loadServerConfig (url: string): Promise<any> {\n  let retries = 1\n  let res: Response | undefined\n\n  while (true) {\n    try {\n      res = await fetch(url, {\n        keepalive: true\n      })\n      if (res === undefined) {\n        // In theory should never get here\n        throw new Error('Failed to load server config')\n      }\n      break\n    } catch (e) {\n      retries++\n      await new Promise((resolve) => setTimeout(resolve, 1000 * Math.min(5, retries)))\n    }\n  }\n\n  return await res.json()\n}\n\nconst openArg = (process.argv.find((it) => it.startsWith('--open=')) ?? '').split('--open=')[1]\nconsole.log('Open passed', openArg)\nlet configPromise: Promise<Config> | undefined\n\nconst expose: IPCMainExposed = {\n  setBadge: (badge: number) => {\n    ipcRenderer.send(IpcMessage.SetBadge, badge)","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/desktop/src/ui/preload.ts#L24-L60","documentation":"The mail service HTTP endpoint in services/mail/pod-mail/src/main.ts rejects a POST to the send-mail route with HTTP 400 when the request body has no 'subject' field. handleSendMail validates required fields (text/html, subject, to, from) sequentially and returns the first missing one as { err: \"'subject' is missing\" }. This is a deliberate input validation guard, not an internal failure.","triggerScenarios":"POSTing to the mail endpoint with a JSON body that includes text or html, to, and from, but omits the 'subject' property (or sends it as null/undefined after JSON serialization drops it).","commonSituations":"Callers building the request dynamically where subject comes from user input or an upstream record that lacks a title; automated notification senders that only set the body; JSON.stringify silently dropping undefined subject values.","solutions":["Add a non-empty 'subject' string to the request body before sending.","If subject is optional by design, pass an empty string or a placeholder like '(no subject)'.","Check the caller code that constructs the payload for undefined subject values being dropped by JSON.stringify.","Return the error to the user or log it client-side instead of retrying the same payload."],"exampleFix":"// before\nawait fetch(mailUrl, { method: 'POST', body: JSON.stringify({ from, to, text }) })\n// after\nawait fetch(mailUrl, { method: 'POST', body: JSON.stringify({ from, to, text, subject: subject ?? '(no subject)' }) })","handlingStrategy":"validation","validationCode":"if (typeof subject !== 'string' || subject.length === 0) {\n  throw new Error('subject is required before calling the mail endpoint')\n}","typeGuard":"function hasSubject(body: unknown): body is { subject: string; [k: string]: unknown } {\n  return typeof body === 'object' && body !== null && typeof (body as any).subject === 'string' && (body as any).subject.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 === \"'subject' is missing\") {\n    // surface a field-level validation message to the user instead of retrying\n  }\n}","preventionTips":["Validate all required mail fields (subject, to, from, text/html) at the call site before building the request.","Avoid undefined fields in payloads — JSON.stringify silently drops them; use explicit defaults like '(no subject)'.","Write a shared payload builder for mail requests so required fields are enforced in one place."],"tags":["http-400","validation","missing-field","mail"],"backgroundTag":"missing-request-field","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}