immich-app/immich · error
Invalid CLIP dimension size
Error message
Invalid CLIP dimension size: ${dimSize} What it means
setDimensionSize reconfigures the smart_search table's embedding dimension for the CLIP model. The requested dimension must be an integer between 1 and 65536 (2^16) — the limit imposed by the halfvec/index representation. Invalid values (NaN, 0, negative, non-integers, >65536) throw before any schema change is made.
Solutions
- Ensure the value is a positive integer ≤ 65536 and matches the ML model's embedding size (e.g. 512, 768, 1152)
- Check the MACHINE_LEARNING env/config for typos or empty values that parse to NaN
- Verify the ML service's model actually outputs the configured dimension, then re-run smart search indexing
- After fixing the dimension, let Immich recreate the smart_search index (it drops and rebuilds it automatically)
Example fix
// before await repo.setDimensionSize(Number(process.env.CLIP_DIM)); // NaN when unset // after const dim = Number(process.env.CLIP_DIM); if (Number.isInteger(dim) && dim >= 1 && dim <= 65536) await repo.setDimensionSize(dim);
Defensive patterns
Strategy: validation
Validate before calling
if (!Number.isInteger(dimSize) || dimSize < 1 || dimSize > 65536) {
throw new Error(`dimSize must be an integer in [1, 65536], got ${dimSize}`);
} Type guard
const isValidDim = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v >= 1 && v <= 65536;
Try / catch
try {
await repo.setDimensionSize(dim);
} catch (e) {
if ((e as Error).message.startsWith('Invalid CLIP dimension size')) {
dim = MODEL_OUTPUT_DIM; // fall back to the model's known embedding size
await repo.setDimensionSize(dim);
} else throw e;
} Prevention
- Parse config values with a strict integer schema (zod) before use
- Cross-check dimension against the deployed ML model's embedding size
- Never pass raw/unparsed env strings to setDimensionSize
When it happens
Trigger: Calling setDimensionSize with a dimSize that fails the zod check: 0, negative, non-integer, NaN, or above 65536 — typically from an environment/config value (e.g. MACHINE_LEARNING clip dimension) parsed incorrectly or from a mismatched ML model configuration.
Common situations: Setting a CLIP dimension that doesn't match the ML model's output (e.g. 512 for a 1152-dim model); an unset/empty env var parsed to NaN; custom model deployments whose embedding size differs from Immich's defaults.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Invalid environment variables: \n
- Unknown CLIP model
- Admin account does not exist
- Album must have an owner
- Asset dimensions are not available for editing
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/fa8d74940bb23a1a.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/repositories/database.repository.ts:328
.min(1)
.max(2 ** 16)
.safeParse(dimSize).success
) {
this.logger.warn(`Could not retrieve dimension size of column '${column}' in table '${table}', assuming 512`);
return 512;
}
return dimSize;
}
async setDimensionSize(dimSize: number): Promise<void> {
if (
!z
.int()
.min(1)
.max(2 ** 16)
.safeParse(dimSize).success
) {
throw new Error(`Invalid CLIP dimension size: ${dimSize}`);
}
// this is done in two transactions to handle concurrent writes
await this.db.transaction().execute(async (trx) => {
await sql`delete from ${sql.table('smart_search')}`.execute(trx);
await trx.schema.alterTable('smart_search').dropConstraint('dim_size_constraint').ifExists().execute();
await sql`alter table ${sql.table('smart_search')} add constraint dim_size_constraint check (array_length(embedding::real[], 1) = ${sql.lit(dimSize)})`.execute(
trx,
);
});
const vectorExtension = await this.getVectorExtension();
await this.db.transaction().execute(async (trx) => {
await sql`drop index if exists clip_index`.execute(trx);
await trx.schema
.alterTable('smart_search')
.alterColumn('embedding', (col) => col.setDataType(sql.raw(`vector(${dimSize})`)))
.execute();View on GitHub (pinned to e55ac299a4)