immich-app/immich · critical · Error
Invalid system config:
Error message
Invalid system config:
What it means
Thrown by the config loader (server/src/utils/config.ts) when the raw system config fails Zod validation against SystemConfigSchema AND it was loaded from a config file (configFile set). The error message aggregates every Zod issue with its path and message. When there is no config file, validation errors are only logged, not thrown.
Solutions
- Read the full error message — each line lists the field path and the Zod issue; fix each one in the config file.
- Compare your config file against the current SystemConfig schema/default template for the installed Immich version.
- Temporarily remove the config file to boot with DB-stored defaults, then re-apply changes field by field.
- Validate the file with a JSON/YAML linter before deploying.
Example fix
// before — config file
{ "ffmpeg": { "crf": -5 } } // out of range
// after
{ "ffmpeg": { "crf": 23 } } Defensive patterns
Strategy: validation
Validate before calling
// validate the config file against the same schema before boot
import { SystemConfigSchema } from 'src/...';
const raw = JSON.parse(readFileSync(configFile, 'utf8'));
const parsed = SystemConfigSchema.safeParse(raw);
if (!parsed.success) { for (const i of parsed.error.issues) console.error(i.path.join('.'), i.message); } Type guard
const isSystemConfig = (v: unknown): v is SystemConfig => SystemConfigSchema.safeParse(v).success;
Try / catch
try { await loadConfig(); }
catch (e) { if (e instanceof Error && e.message.startsWith('Invalid system config')) { /* print issues, fall back to DB defaults */ } else throw e; } Prevention
- Lint/validate the config file in CI against SystemConfigSchema before deploying.
- Keep a version-pinned reference config and diff yours against it on upgrades.
- Remove the config file to boot with DB defaults when unsure.
When it happens
Trigger: Immich started with IMMICH_CONFIG_FILE pointing at a JSON/YAML file whose values fail schema validation: wrong types, out-of-range numbers, unknown enum values, or structurally invalid nested objects.
Common situations: Editing the config file by hand and introducing a typo or invalid enum (e.g. ffmpeg.accel set to an unsupported hardware acceleration, or a negative CRF); upgrading Immich where a config field was renamed/removed and the old file no longer parses; copying a config snippet from an incompatible version.
Related errors
- Invalid environment variables:
- Invalid environment variables: \n
- Invalid system config
- error instanceof Error ? error.message : error
- {error.message}
AI-assisted analysis of immich-app/immich@37e033a09d (2026-08-12).
Data as JSON: /api/errors/30e4571678a6be52.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/utils/config.ts:110
const unknownKeys = _.cloneDeep(rawConfig);
for (const property of getKeysDeep(defaults)) {
unsetDeep(unknownKeys, property);
}
if (!_.isEmpty(unknownKeys)) {
logger.warn(`Unknown keys found: ${JSON.stringify(unknownKeys, null, 2)}`);
}
// validate with Zod schema
const result = AdminConfigDto.schema.safeParse(rawConfig);
if (!result.success) {
const messages = ['Invalid system config: '];
for (const issue of result.error.issues) {
const path = issue.path.join('.');
messages.push(` - [${path}] ${issue.message}`);
}
if (configFile) {
throw new Error(messages.join('\n'));
}
logger.error('Validation error', messages);
}
const config = (result.success ? result.data : rawConfig) as SystemConfig;
if (config.server.externalDomain.length > 0) {
const domain = new URL(config.server.externalDomain);
const externalDomain =
domain.password && domain.username
? `${domain.protocol}//${domain.username}:${domain.password}@${domain.host}`
: domain.origin;
config.server.externalDomain = externalDomain;
}
if (!config.ffmpeg.acceptedVideoCodecs.includes(config.ffmpeg.targetVideoCodec)) {View on GitHub (pinned to 37e033a09d)