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

  1. Ensure the value is a positive integer ≤ 65536 and matches the ML model's embedding size (e.g. 512, 768, 1152)
  2. Check the MACHINE_LEARNING env/config for typos or empty values that parse to NaN
  3. Verify the ML service's model actually outputs the configured dimension, then re-run smart search indexing
  4. 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

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


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)