hcengineering/platform · critical · Error

Failed to fetch config

Error message

Failed to fetch config

What it means

loadServerConfig fetches <server-url>/config.json, which describes service endpoints (accounts, collaborator, etc.). If the fetch response is not ok (404, 500, etc.), it throws 'Failed to fetch config'. The client cannot discover service URLs without this file.

Source

Thrown at foundations/core/packages/api-client/src/config.ts:31

// limitations under the License.
//

import { concatLink } from '@hcengineering/core'

export interface ServerConfig {
  ACCOUNTS_URL: string
  COLLABORATOR_URL: string
  FILES_URL: string
  UPLOAD_URL: string
}

export async function loadServerConfig (url: string): Promise<ServerConfig> {
  const configUrl = concatLink(url, '/config.json')
  const res = await fetch(configUrl, { keepalive: true })
  if (res.ok) {
    return (await res.json()) as ServerConfig
  }
  throw new Error('Failed to fetch config')
}

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Open <url>/config.json in a browser/curl and confirm it returns valid JSON with 200.
  2. Correct the base URL passed to connect/loadServerConfig.
  3. Check the server deployment includes config.json and the reverse proxy routes it correctly.
  4. Check network/DNS/CORS issues preventing the fetch.

Example fix

// before
const client = await connect('https://wrong-host.example.com', { workspace: 'ws' })
// after
const res = await fetch('https://huly.example.com/config.json')
if (!res.ok) throw new Error('config.json unreachable: ' + res.status)
const client = await connect('https://huly.example.com', { workspace: 'ws' })
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(new URL('/config.json', baseUrl), { method: 'HEAD' })
if (!res.ok) throw new Error(`Server at ${baseUrl} is not a Huly frontend (config.json ${res.status})`)

Type guard

function isServerConfig(v: unknown): v is ServerConfig {
  return typeof v === 'object' && v !== null && 'ACCOUNTS_URL' in v
}

Try / catch

async function loadConfigWithRetry(url: string, attempts = 3): Promise<ServerConfig> {
  for (let i = 0; i < attempts; i++) {
    try { return await loadServerConfig(url) }
    catch (e) { if (i === attempts - 1) throw new Error(`Cannot reach ${url}/config.json — check the URL, proxy and network`, { cause: e }) ; await sleep(1000 * 2 ** i) }
  }
  throw new Error('unreachable')
}

Prevention

When it happens

Trigger: Calling connect/getWorkspaceToken against a URL where /config.json is missing, returns 404, or the server is down/proxy returns an error page.

Common situations: Pointing the client at a wrong or non-Huly frontend URL, server behind a proxy that strips/rewrites config.json, deployment where static config.json was not deployed, network outage or DNS misconfiguration, CORS-blocked fetch failing the response.

Related errors


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