hcengineering/platform · error · Error

Failed to load server config

Error message

Failed to load server config

What it means

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.

Source

Thrown at desktop/src/ui/preload.ts:42

    const newPath = path.slice(1)
    return `${host}${newPath}`
  } else {
    return `${host}${path}`
  }
}

async function loadServerConfig (url: string): Promise<any> {
  let retries = 1
  let res: Response | undefined

  while (true) {
    try {
      res = await fetch(url, {
        keepalive: true
      })
      if (res === undefined) {
        // In theory should never get here
        throw new Error('Failed to load server config')
      }
      break
    } catch (e) {
      retries++
      await new Promise((resolve) => setTimeout(resolve, 1000 * Math.min(5, retries)))
    }
  }

  return await res.json()
}

const openArg = (process.argv.find((it) => it.startsWith('--open=')) ?? '').split('--open=')[1]
console.log('Open passed', openArg)
let configPromise: Promise<Config> | undefined

const expose: IPCMainExposed = {
  setBadge: (badge: number) => {
    ipcRenderer.send(IpcMessage.SetBadge, badge)

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Add a non-empty 'subject' string to the request body before sending.
  2. If subject is optional by design, pass an empty string or a placeholder like '(no subject)'.
  3. Check the caller code that constructs the payload for undefined subject values being dropped by JSON.stringify.
  4. Return the error to the user or log it client-side instead of retrying the same payload.

Example fix

// before
await fetch(mailUrl, { method: 'POST', body: JSON.stringify({ from, to, text }) })
// after
await fetch(mailUrl, { method: 'POST', body: JSON.stringify({ from, to, text, subject: subject ?? '(no subject)' }) })
Defensive patterns

Strategy: validation

Validate before calling

if (typeof subject !== 'string' || subject.length === 0) {
  throw new Error('subject is required before calling the mail endpoint')
}

Type guard

function hasSubject(body: unknown): body is { subject: string; [k: string]: unknown } {
  return typeof body === 'object' && body !== null && typeof (body as any).subject === 'string' && (body as any).subject.length > 0
}

Try / catch

const res = await fetch(mailUrl, { method: 'POST', body })
if (res.status === 400) {
  const { err } = await res.json()
  if (err === "'subject' is missing") {
    // surface a field-level validation message to the user instead of retrying
  }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/de6e83a7958deddb. Report an issue: GitHub.