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
- Read the thrown message: it names the exact module and key — fix that env var or override to match the expected type/format.
- Check the key's definition in packages/backend/server/src/base/config (its zod schema and env parser) for the accepted format.
- Remove stale overrides left over from previous versions.
- 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
- Run the server's config stage in CI with production env to catch invalid values before deploy.
- Keep .env files versioned per environment and diff them after upgrades.
- Read each key's zod definition in packages/backend/server/src/base/config when unsure of the accepted format.
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
- captcha_verification_failed
- doc_default_role_can_not_be_owner
- email_token_not_found
- expect_to_grant_doc_user_roles
- expect_to_publish_doc
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)