toeverything/AFFiNE · warning · InvalidAppConfigInput
invalid_app_config_input
invalid_app_config_input
Error message
Invalid app config input: ${message} What it means
Thrown by `ServerService.updateConfig` when `configFactory.validate(updates)` returns one or more validation errors. The error messages are joined with newlines and passed as `message` on `InvalidAppConfigInput` (category `invalid_input`), aborting the save before anything reaches the `appConfig` table.
Source
Thrown at packages/backend/server/src/core/config/service.ts:79
this.#features.delete(feature);
}
getConfig() {
return this.configFactory.clone();
}
validateConfig(updates: Array<{ module: string; key: string; value: any }>) {
return this.configFactory.validate(updates);
}
async updateConfig(
user: string,
updates: Array<{ module: string; key: string; value: any }>
): Promise<DeepPartial<AppConfig>> {
const errors = this.validateConfig(updates);
if (errors?.length) {
throw new InvalidAppConfigInput({
message: errors.map(error => error.message).join('\n'),
});
}
const promises = await this.models.appConfig.save(
user,
updates.map(update => ({
key: `${update.module}.${update.key}`,
value: update.value,
}))
);
const overrides: DeepPartial<AppConfig> = {};
// only take successfully saved configs
promises.forEach(promise => {
if (promise.status === 'fulfilled') {
set(overrides, promise.value.id, promise.value.value);
} else {View on GitHub (pinned to 26c515e050)
Solutions
- Run `server.validateConfig(updates)` (or the same schema on the client) before calling `updateConfig` and show per-field errors.
- Inspect the returned `message` string — it lists every failing field; fix each cited `module.key`.
- Re-fetch the config descriptor/schema after a server upgrade to learn the current valid keys and types.
- Ensure each entry uses `{ module, key, value }` shape and that `value` matches the declared type.
Example fix
// before
await server.updateConfig(userId, updates);
// after
const errors = server.validateConfig(updates);
if (errors?.length) {
// errors: [{ field, message }...] — surface per-field in the admin form
setFieldErrors(errors);
return;
}
await server.updateConfig(userId, updates); Defensive patterns
Strategy: validation
Validate before calling
// Validate config updates against the same factory before submitting
const updates = [
{ module: 'auth', key: 'session.timeout', value: 3600 },
];
const errors = server.validateConfig(updates);
if (errors?.length) {
// errors: [{ field, message }, ...]
setFieldErrors(errors.map(e => ({ path: e.field, message: e.message })));
return;
}
await server.updateConfig(userId, updates); Type guard
interface ConfigUpdate {
module: string;
key: string;
value: unknown;
}
function isConfigUpdate(v: unknown): v is ConfigUpdate {
return typeof v === 'object' && v !== null &&
typeof (v as ConfigUpdate).module === 'string' &&
typeof (v as ConfigUpdate).key === 'string' &&
'value' in v;
} Try / catch
try {
await server.updateConfig(userId, updates);
} catch (e) {
if (e?.extensions?.code === 'invalid_app_config_input') {
// e.extensions.message lists every failing field, newline-separated
setFormErrors(e.extensions.message.split('\n'));
return;
}
throw e;
} Prevention
- Always call `validateConfig` before `updateConfig` and surface per-field errors.
- After a server upgrade, re-fetch the config descriptor to learn valid keys/types.
- Send each update as `{ module, key, value }` with a value matching the declared type.
- Parse the returned `message` newline-list to fix every cited field at once.
When it happens
Trigger: Submitting a config update whose `module.key` path is unknown, whose value type mismatches the schema, or whose value violates a declared constraint (range/enum/format).
Common situations: Admin UI posting a mistyped key or wrong-type value; version drift where a config key was renamed/removed but the caller still sends the old shape; copy-pasted JSON with the wrong nesting.
Related errors
- bad_request
- SchemaValidateError
- bad_request
- Invalid config for module [${module}] with key [${key}] Valu
- email_token_not_found
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/112cadb859e13a14.
Report an issue: GitHub.