toeverything/AFFiNE · error · Error

Invalid `server.externalUrl` configured. It must be a valid…

Error message

Invalid `server.externalUrl` configured. It must be a valid url.

What it means

UrlHelper.init validates server.externalUrl on config init/change and throws when the configured value does not parse as a valid URL, preventing the server from booting with a base URL that would produce broken links.

Solutions

  1. Set server.externalUrl in the config (or AFFINE_SERVER_EXTERNAL_URL env) to a fully-qualified URL including protocol, e.g. https://affine.example.com.
  2. Remove the externalUrl setting if you don't need absolute URLs in emails/redirects — the server will fall back to request-derived origins.
  3. Validate the URL locally with new URL(value) before deploying the config.

Example fix

# config.yaml
server:
  externalUrl: 'https://affine.example.com' # must include scheme and host
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/backend/server/src/base/helpers/url.ts:53 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18). Data as JSON: /api/errors/a5703b5da36dd53d. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/base/helpers/url.ts:49

  redirectAllowHosts!: string[];

  origin!: string;
  allowedOrigins!: string[];
  baseUrl!: string;

  constructor(
    private readonly config: Config,
    private readonly cls?: ClsService
  ) {
    this.init();
  }

  @OnEvent('config.changed')
  @OnEvent('config.init')
  init() {
    if (this.config.server.externalUrl) {
      if (!this.verify(this.config.server.externalUrl)) {
        throw new Error(
          'Invalid `server.externalUrl` configured. It must be a valid url.'
        );
      }

      const externalUrl = new URL(this.config.server.externalUrl);

      this.origin = externalUrl.origin;
      this.baseUrl =
        externalUrl.origin + externalUrl.pathname.replace(/\/$/, '');
    } else {
      this.origin = this.convertHostToOrigin(this.config.server.host);
      this.baseUrl = this.origin + this.config.server.path;
    }

    this.redirectAllowHosts = [this.baseUrl];

    this.allowedOrigins = [this.origin];
    if (this.config.server.hosts.length > 0) {

View on GitHub (pinned to 2af30773ae)