toeverything/AFFiNE · critical · Error

Invalid config for module

Error message

Invalid config for module [${module}] with key [${key}]
Value: ${JSON.stringify(defaultValue)}
Error: ${issue.message}

What it means

During AFFiNE server startup, the config register resolves each key's value (defaults, then env override parsed by parseEnvValue) and validates it with the key's zod validator (desc.validate). On failure it throws an Error listing the module, key, JSON-encoded value, and the zod issue message, aborting boot. So the server refuses to start while any single config value violates its declared schema.

Solutions

  1. Read the thrown message: it names the exact module and key — fix that env var or override to match the expected type/format.
  2. Check the key's definition in packages/backend/server/src/base/config (its zod schema and env parser) for the accepted format.
  3. Remove stale overrides left over from previous versions.
  4. Validate the full environment in CI (boot the config stage) before deploying.

Example fix

# before
AFFINE_SERVER_URL="not a url"  # fails url validation for its module/key

# after
AFFINE_SERVER_URL="https://affine.example.com"
Defensive patterns

Strategy: validation

Validate before calling

// fail fast at deploy time instead of at server boot
import { z } from 'zod';
const boolish = z.union([z.boolean(), z.enum(['true', 'false']).transform(v => v === 'true')]);
// mirror each env key's expected shape and parse process.env before startup

Type guard

const isValidEnvValue = (value: string, schema: z.ZodType<unknown>): boolean =>
  schema.safeParse(value).success;

Try / catch

try {
  await app.init(); // config registration runs here
} catch (e) {
  if (e instanceof Error && e.message.includes('Invalid config for module')) {
    // parse module/key from the message, fix the env var, and exit non-zero
    console.error(e.message);
    process.exit(1);
  } else throw e;
}

Prevention

When it happens

Trigger: Setting an env var to a value with the wrong type/format for its key (malformed URL, non-numeric value for a number key, invalid boolean); a typo'd or stale override in .env; deploying with env vars from an older incompatible AFFiNE version.

Common situations: Docker/Kubernetes env typos in AFFiNE_-prefixed variables; config schema tightened after an upgrade so previously accepted values now fail; copy-pasted .env files between environments.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at packages/backend/server/src/base/config/register.ts:370

  for (const [module, defs] of Object.entries(APP_CONFIG_DESCRIPTORS)) {
    const modulizedConfig = {};

    for (const [key, desc] of Object.entries(defs)) {
      let defaultValue = desc.default;

      if (desc.env) {
        const [env, parser] = desc.env;
        const envValue = envs[env];
        if (envValue) {
          defaultValue = parseEnvValue(envValue, parser);
        }
      }

      const { success, error } = desc.validate(defaultValue);

      if (!success) {
        throw new Error(
          error.issues
            .map(issue => {
              return `Invalid config for module [${module}] with key [${key}]
Value: ${JSON.stringify(defaultValue)}
Error: ${issue.message}`;
            })
            .join('\n')
        );
      }

      set(modulizedConfig, key, defaultValue);
    }

    // @ts-expect-error all keys are known
    config[module] = modulizedConfig;
  }

  CONFIG_JSON_PATHS.forEach(path => {

View on GitHub (pinned to b4c8548c09)